如何提高查询速度

时间:2016-02-10 06:46:50

标签: sql postgresql postgresql-performance

我正在尝试加速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列,传输码和inputdatetime

查询说明

"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"

1 个答案:

答案 0 :(得分:2)

从解释中可以看出,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

可能会有所帮助link