Как увеличить скорость запросов

я пытаюсь ускорить некоторый запрос в postgresql, в настоящее время я думаю, что он медленный, учитывая, что я хочу получить диапазон дат, в настоящее время у меня есть это:

select enc.inputdatetime::date dateMed, enc.transmissioncode,
   max(det.devicelevel) devicelevel, max(det.pressure) pressure,
   max(det.battery) battery,enc.remotelocationid,max(det.loop1con) loop1con 
from tl.tlinputdetail det 
inner join tl.tlinputtable enc on det.oldmedicionid = enc.oldmedicionid 
   where TRIM(enc.transmissioncode)= '005'
   and enc.inputdatetime::date between '2015-12-12' and '2016-11-12'                           
group by 
   enc.transmissioncode,enc.remotelocationid,enc.inputdatetime::date
order by 
   enc.inputdatetime::date asc;

Общее время выполнения запроса: 47,6 с. Получено 60 строк.

Как я могу увеличить свой запрос? У меня есть индекс в обеих таблицах, в столбце oldmedicionid, коде передачи и вводе даты и времени

Объяснение запроса

"Sort  (cost=105519.94..105519.96 rows=7 width=30)"
"  Sort Key: ((enc.inputdatetime)::date)"
"  ->  HashAggregate  (cost=105519.76..105519.85 rows=7 width=30)"
"        Group Key: (enc.inputdatetime)::date, enc.transmissioncode, enc.remotelocationid"
"        ->  Nested Loop  (cost=0.43..105517.50 rows=129 width=30)"
"              ->  Seq Scan on tlinputtable enc  (cost=0.00..104881.30 rows=64 width=31)"
"                    Filter: (((inputdatetime)::date >= '2015-12-12'::date) AND ((inputdatetime)::date <= '2016-11-12'::date) AND (btrim((transmissioncode)::text) = '005'::text))"
"              ->  Index Scan using tlinputdetail_oldmedicionididx on tlinputdetail det  (cost=0.43..9.90 rows=4 width=15)"
"                    Index Cond: (oldmedicionid = enc.oldmedicionid)"

Подробно объяснить, проанализировать, подробно

 "Sort  (cost=105519.94..105519.96 rows=7 width=30) (actual time=57948.774..57948.782 rows=61 loops=1)"
"  Output: ((enc.inputdatetime)::date), enc.transmissioncode, (max((det.devicelevel)::text)), (max((det.pressure)::text)), (max((det.battery)::text)), enc.remotelocationid, (max((det.loop1con)::text))"
"  Sort Key: ((enc.inputdatetime)::date)"
"  Sort Method: quicksort  Memory: 29kB"
"  ->  HashAggregate  (cost=105519.76..105519.85 rows=7 width=30) (actual time=57948.655..57948.717 rows=61 loops=1)"
"        Output: ((enc.inputdatetime)::date), enc.transmissioncode, max((det.devicelevel)::text), max((det.pressure)::text), max((det.battery)::text), enc.remotelocationid, max((det.loop1con)::text)"
"        Group Key: (enc.inputdatetime)::date, enc.transmissioncode, enc.remotelocationid"
"        ->  Nested Loop  (cost=0.43..105517.50 rows=129 width=30) (actual time=21.621..57708.114 rows=62181 loops=1)"
"              Output: (enc.inputdatetime)::date, enc.transmissioncode, enc.remotelocationid, det.devicelevel, det.pressure, det.battery, det.loop1con"
"              ->  Seq Scan on tl.tlinputtable enc  (cost=0.00..104881.30 rows=64 width=31) (actual time=0.143..1641.444 rows=20727 loops=1)"
"                    Output: enc.inputid, enc.inputdatetime, enc.packagesqty, enc.remotelocationid, enc.transmissioncode, enc.oldmedicionid"
"                    Filter: (((enc.inputdatetime)::date >= '2015-12-12'::date) AND ((enc.inputdatetime)::date <= '2016-11-12'::date) AND (btrim((enc.transmissioncode)::text) = '005'::text))"
"                    Rows Removed by Filter: 2556266"
"              ->  Index Scan using tlinputdetail_oldmedicionididx on tl.tlinputdetail det  (cost=0.43..9.90 rows=4 width=15) (actual time=2.467..2.699 rows=3 loops=20727)"
"                    Output: det.inputdetailid, det.inputid, det.devicelevel, det.pressure, det.battery, det.inputdatetime, det.devicecontrol, det.volumecon, det.pressurevolumecon, det.weightcon, det.decimalunit, det.weightunitcon, det.loop1con, det.loop2co (...)"
"                    Index Cond: (det.oldmedicionid = enc.oldmedicionid)"
"Planning time: 0.549 ms"
"Execution time: 57948.902 ms"

person Max Pinto    schedule 10.02.2016    source источник
comment
Можете ли вы предоставить план объяснения?   -  person Tah    schedule 10.02.2016
comment
конечно, я добавил это   -  person Max Pinto    schedule 10.02.2016
comment
вывод explain (analyze, verbose) был бы более полезным. Вы можете прочитать это: stackoverflow.com/tags/postgresql-performance/info   -  person a_horse_with_no_name    schedule 10.02.2016
comment
Спасибо, я прочитаю, я просто включаю объяснение запроса   -  person Max Pinto    schedule 10.02.2016
comment
Статистика по tl.tlinputdetail кажется устаревшей. Postgres ожидает 64 строки, но содержит 20727. Изменится ли план после запуска analyze tl.tlinputdetail   -  person a_horse_with_no_name    schedule 10.02.2016
comment
Мне кажется, вы могли бы использовать частичный индекс для tl.tlinputtable, где transmissioncode = '005'.   -  person Daniel Lyons    schedule 10.02.2016
comment
Ну, код передачи «005» не является статическим, я использую его для объяснения, но он динамический   -  person Max Pinto    schedule 10.02.2016
comment
Тогда я бы рассмотрел многостолбцовый индекс для transmissioncode и tlinputtable. В зависимости от того, как данные складываются на практике, один порядок может работать лучше, чем другой; Я бы попробовал оба способа и посмотрел, какой из них более полезен.   -  person Daniel Lyons    schedule 10.02.2016
comment
Если у вас есть индекс для transmissioncode, он не будет использоваться из-за использования функции trim(). Зачем тебе это надо? Если вы не можете избавиться от него, вам нужно создать индекс для trim(transmissioncode), чтобы он соответствовал условию вашего запроса. Но комбинированный индекс для (transmissioncode, inputdatetime), вероятно, будет хорошей идеей для начала.   -  person a_horse_with_no_name    schedule 10.02.2016
comment
inputdatetime - это поле метки времени, или я что-то пропустил? вы должны попытаться создать индекс на inputdatetime CREATE INDEX ON tl.tlinputtable ((inputdatetime::date) ASC NULLS LAST);   -  person LongBeard_Boldy    schedule 10.02.2016
comment
вы также можете попытаться увеличить целевую статистику столбца в tlinputtable.oldmedicionid, чтобы получить лучшую статистику и оценки. ожидаемые 64 строки вместо нескольких тысяч иногда вызывают беспокойство   -  person LongBeard_Boldy    schedule 10.02.2016


Ответы (1)


Как я вижу из объяснения, tlinputdetail — это таблица устройств, tlinputtable — это журналоподобная таблица, которая содержит фактические основные данные. Объяснение показывает, что используется только индекс для tlinputdetail, и причина того, что запрос медленный, заключается в том, что ни одно условие фильтра не использует какой-либо индекс, и база данных вынуждена использовать сканирование последовательности в tlinputtable, которая, как я полагаю, является довольно большой таблицей. Чтобы оптимизировать этот запрос, вы должны создать 2 индекса: на inputdatetime как

CREATE INDEX ON tl.tlinputtable ((inputdatetime::date) ASC NULLS LAST);

и по коду передачи как

CREATE INDEX ON tl.tlinputtable ((trim(transmissioncode)) ASC NULLS LAST);

Редактировать:

для метки времени с часовым поясом как

CREATE INDEX ON tl.tlinputtable  (DATE(inputdatetime AT TIME ZONE 'UTC') ASC NULLS LAST);

и используйте вместо этого что-то вроде этого

 (date(timezone('UTC'::text, inputdatetime )) between '2015-01-01'::date and ....)

используйте часовой пояс, который вам нужен, вместо UTC

может помочь ссылка

person LongBeard_Boldy    schedule 10.02.2016
comment
Спасибо, выполнив первый запрос, я получил следующее: функции в индексном выражении должны быть помечены как IMMUTABLE, как я могу это исправить? - person Max Pinto; 10.02.2016
comment
какую версию postgresql вы используете? ах, tlinputtable должна быть временной меткой с часовым поясом... - person LongBeard_Boldy; 11.02.2016
comment
Есть ли шанс изменить это поле на метку времени без часового пояса? - person LongBeard_Boldy; 11.02.2016
comment
никак, этого не может быть, и вы правы, непреложная ошибка была в том, что - person Max Pinto; 11.02.2016