Слишком медленный запрос только для 4 таблиц по 50000 строк в каждой - PullRequest
0 голосов
/ 04 декабря 2018

Я боролся часами и не могу понять, почему этот запрос занимает слишком много времени (> 60 минут).Все 4 таблицы содержат менее 50 000 записей.

Также, если я удаляю любую таблицу (gel6, gf6 или ger6), выполнение запроса занимает менее 500 мс.Что я делаю неправильно?

Объяснить план: https://explain.depesz.com/s/ldm2

 SELECT COUNT(*)
 FROM agroapp.ganado g
 INNER JOIN (SELECT gel5.ganado_id, gel5.estado_leche  
             FROM agroapp.ganado_estado_leche gel5  
             INNER JOIN (SELECT MAX(gel3.ganado_estado_leche_id) ganado_estado_leche_id  
                         FROM agroapp.ganado_estado_leche gel3  
                         INNER JOIN (SELECT gel.ganado_id, MAX(gel.created) created  
                                     FROM agroapp.ganado_estado_leche gel   
                                     GROUP BY gel.ganado_id) gel2 ON (gel2.ganado_id = gel3.ganado_id AND gel2.created = gel3.created)  
                         GROUP BY gel3.ganado_id) gel4 ON gel4.ganado_estado_leche_id = gel5.ganado_estado_leche_id  
            ) gel6 ON gel6.ganado_id = g.ganado_id
 INNER JOIN (SELECT gf5.ganado_id, gf5.fundo_id  
             FROM agroapp.ganado_fundo gf5  
             INNER JOIN (SELECT MAX(gf3.ganado_fundo_id) ganado_fundo_id  
                         FROM agroapp.ganado_fundo gf3  
                         INNER JOIN (SELECT gf.ganado_id, MAX(gf.created) created  
                                     FROM agroapp.ganado_fundo gf  
                                     GROUP BY gf.ganado_id) gf2 ON (gf2.ganado_id = gf3.ganado_id AND gf2.created = gf3.created)    
                         GROUP BY gf3.ganado_id) gf4 ON gf4.ganado_fundo_id = gf5.ganado_fundo_id  
            ) gf6 ON gf6.ganado_id = g.ganado_id
 INNER JOIN (SELECT ger5.ganado_id, ger5.estado_reproductivo  
             FROM agroapp.ganado_estado_reproductivo ger5  
             INNER JOIN (SELECT MAX(ger3.ganado_estado_reproductivo_id) ganado_estado_reproductivo_id  
                         FROM agroapp.ganado_estado_reproductivo ger3  
                         INNER JOIN (SELECT ger.ganado_id, MAX(ger.created) created  
                                     FROM agroapp.ganado_estado_reproductivo ger  
                                     GROUP BY ger.ganado_id) ger2 ON (ger2.ganado_id = ger3.ganado_id AND ger2.created = ger3.created)  
                         GROUP BY ger3.ganado_id) ger4 ON ger4.ganado_estado_reproductivo_id = ger5.ganado_estado_reproductivo_id  
            ) ger6 ON ger6.ganado_id = g.ganado_id
WHERE g.organizacion_id = 21

Таблицы

CREATE TABLE agroapp.ganado_estado_leche
(
  ganado_estado_leche_id serial NOT NULL,
  organizacion_id integer NOT NULL,
  isactive character(1) NOT NULL DEFAULT 'Y'::bpchar,
  created timestamp without time zone NOT NULL DEFAULT now(),
  createdby numeric(10,0) NOT NULL,
  updated timestamp without time zone NOT NULL DEFAULT now(),
  updatedby numeric(10,0) NOT NULL,
  estado_leche character varying(80) NOT NULL,
  ganado_id integer NOT NULL,
  fecha_manejo timestamp without time zone NOT NULL,
  CONSTRAINT ganado_estado_leche_pk PRIMARY KEY (ganado_estado_leche_id),
  CONSTRAINT ganado_fk FOREIGN KEY (ganado_id)
      REFERENCES agroapp.ganado (ganado_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE agroapp.ganado_fundo
(
  ganado_fundo_id serial NOT NULL,
  organizacion_id integer NOT NULL,
  isactive character(1) NOT NULL DEFAULT 'Y'::bpchar,
  created timestamp without time zone NOT NULL DEFAULT now(),
  createdby numeric(10,0) NOT NULL,
  updated timestamp without time zone NOT NULL DEFAULT now(),
  updatedby numeric(10,0) NOT NULL,
  fundo_id integer NOT NULL,
  ganado_id integer NOT NULL,
  CONSTRAINT ganado_fundo_pk PRIMARY KEY (ganado_fundo_id),
  CONSTRAINT ganado_fk FOREIGN KEY (ganado_id)
      REFERENCES agroapp.ganado (ganado_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE agroapp.ganado_estado_reproductivo
(
  ganado_estado_reproductivo_id serial NOT NULL,
  organizacion_id integer NOT NULL,
  isactive character(1) NOT NULL DEFAULT 'Y'::bpchar,
  created timestamp without time zone NOT NULL DEFAULT now(),
  createdby numeric(10,0) NOT NULL,
  updated timestamp without time zone NOT NULL DEFAULT now(),
  updatedby numeric(10,0) NOT NULL,
  estado_reproductivo character varying(80) NOT NULL,
  ganado_id integer NOT NULL,
  fecha_manejo timestamp without time zone NOT NULL,
  CONSTRAINT ganado_estado_reproductivo_pk PRIMARY KEY (ganado_estado_reproductivo_id),
  CONSTRAINT ganado_fk FOREIGN KEY (ganado_id)
      REFERENCES agroapp.ganado (ganado_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

CREATE TABLE agroapp.ganado
(
  ganado_id serial NOT NULL,
  organizacion_id integer NOT NULL,
  isactive character(1) NOT NULL DEFAULT 'Y'::bpchar,
  created timestamp without time zone NOT NULL DEFAULT now(),
  createdby numeric(10,0) NOT NULL,
  updated timestamp without time zone NOT NULL DEFAULT now(),
  updatedby numeric(10,0) NOT NULL,
  fecha_nacimiento timestamp without time zone NOT NULL,
  tipo_ganado character varying(80) NOT NULL,
  diio_id integer NOT NULL,
  fundo_id integer NOT NULL,
  raza_id integer NOT NULL,
  estado_reproductivo character varying(80) NOT NULL,
  estado_leche character varying(80),
  CONSTRAINT ganado_pk PRIMARY KEY (ganado_id),
  CONSTRAINT diio_fk FOREIGN KEY (diio_id)
      REFERENCES agroapp.diio (diio_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT fundo_fk FOREIGN KEY (fundo_id)
      REFERENCES agroapp.fundo (fundo_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION,
  CONSTRAINT raza_fk FOREIGN KEY (raza_id)
      REFERENCES agroapp.raza (raza_id) MATCH SIMPLE
      ON UPDATE NO ACTION ON DELETE NO ACTION
)

1 Ответ

0 голосов
/ 11 декабря 2018

Дизайн таблицы

  • Это очень похоже на столбец boolean (да / нет):

    isactive character(1) NOT NULL DEFAULT 'Y'::bpchar
    

    Если такзамените на:

    isactive bool NOT NULL DEFAULT TRUE
    
  • Если вы можете каким-либо образом задействовать несколько временных зон, используйте timestamptz вместо timestamp здесь:

    created timestamp without time zone NOT NULL DEFAULT now(),
    

По умолчанию now() выдает timestamptz и после приведения присваивания приводит к текущему времени в соответствии с часовым поясом сеанса.Т.е. значение меняется с timezone сеанса, который является скрытой точкой отказа.См .:
- Игнорирование часовых поясов в целом в Rails и PostgreSQL

И:

createdby numeric(10,0) NOT NULL

и др.похоже, они действительно должны быть просто integer.(Или, может быть, bigint, если вы действительно думаете, что можете прожечь более 2147483648 чисел ...)

Запрос

Просмотр первого подзапроса:

 SELECT gel5.ganado_id, gel5.estado_leche  
 FROM agroapp.ganado_estado_leche gel5  
 INNER JOIN (
    SELECT MAX(gel3.ganado_estado_leche_id) ganado_estado_leche_id  
    FROM agroapp.ganado_estado_leche gel3  
    INNER JOIN (
       SELECT gel.ganado_id, MAX(gel.created) created  
       FROM agroapp.ganado_estado_leche gel   
       GROUP BY gel.ganado_id
       ) gel2 ON (gel2.ganado_id = gel3.ganado_id AND gel2.created = gel3.created)  
    GROUP BY gel3.ganado_id
    ) gel4 ON gel4.ganado_estado_leche_id = gel5.ganado_estado_leche_id

Внутренний подзапрос получает макс.created за ganado_id, следующий - максимум ganado_estado_leche_id из этих строк.И, наконец, вы присоединяетесь и извлекаете все ganado_id, которые появляются в сочетании с указанным максимумом ganado_estado_leche_id на раздел.Мне трудно это понять, но это можно упростить до:

SELECT gel2.ganado_id
FROM   agroapp.ganado_estado_leche gel2
JOIN  (
   SELECT DISTINCT ON (ganado_id) ganado_estado_leche_id
   FROM   agroapp.ganado_estado_leche
   ORDER  BY ganado_id, created DESC NULLS LAST, ganado_estado_leche_id DESC NULLS LAST
   ) gel1 USING (ganado_estado_leche_id)

См .:

Похоже, неправильный запрос для меня.То же самое с остальной частью запроса: объединения умножают строки нечетным способом.Не уверен, что вы пытаетесь сосчитать, но я сомневаюсь, что запрос имеет значение именно это.Вы не предоставили достаточно информации, чтобы понять это.

...