我试图确定为什么一个相当简单的聚合查询要花这么长时间在单个表上执行。该表称为绘图,其为[id, device_id, time, ...]
。有两个索引,即UNIQUE(id)
和UNIQUE(device_id, time)
。
查询很简单:
SELECT device_id, MIN(time)
FROM plots
GROUP BY device_id
对我来说,这应该很快,但是要花3+
分钟。该表具有〜4,500万行,大致在1200
个左右的device_id中平均分配。
EXPLAIN用于查询:
Finalize GroupAggregate (cost=1502955.41..1503055.97 rows=906 width=12)
Group Key: device_id
-> Gather Merge (cost=1502955.41..1503052.35 rows=906 width=12)
Workers Planned: 1
-> Sort (cost=1501955.41..1501955.86 rows=906 width=12)
Sort Key: device_id
-> Partial HashAggregate (cost=1501943.79..1501946.51 rows=906 width=12)
Group Key: device_id
-> Parallel Seq Scan on plots (cost=0.00..1476417.34 rows=25526447 width=12)
说明使用where device_id = xxx
进行查询:
GroupAggregate (cost=398.86..78038.77 rows=906 width=12)
Group Key: device_id
-> Bitmap Heap Scan on plots (cost=398.86..77992.99 rows=43065 width=12)
Recheck Cond: (device_id = 6780)
-> Bitmap Index Scan on index_plots_on_device_id_and_time (cost=0.00..396.71 rows=43065 width=0)
Index Cond: (device_id = 6780)
我已经完成VACUUM (FULL, ANALYZE)
和REINDEX DATABASE
。
我也尝试过通过分区查询来实现相同的目的。
是否有任何使它更快的指针?还是我只是不喜欢桌子的大小。索引似乎应该没问题。也许我缺少一些东西...
编辑/更新:
问题目前似乎已经解决,尽管我不确定为什么。我删除并重建了索引很多次,突然查询只花了大约7秒钟,这是可以接受的。值得注意的是,今天早晨,我删除了索引并创建了一个具有反向列顺序(time, device_id)
的新索引,但我惊讶地看到良好的结果。然后,我恢复到之前的索引,结果得到了进一步改善。我将重新创建生产数据库,并尝试追溯步骤并发布更新。我应该担心查询计划程序将来会失败吗?
具有分析的当前说明(根据要求):
Finalize GroupAggregate (cost=1000.12..480787.58 rows=905 width=12) (actual time=36.299..7530.403 rows=916 loops=1)
Group Key: device_id
Buffers: shared hit=135087 read=40325
I/O Timings: read=138.419
-> Gather Merge (cost=1000.12..480783.96 rows=905 width=12) (actual time=36.226..7552.052 rows=1829 loops=1)
Workers Planned: 1
Workers Launched: 1
Buffers: shared hit=509502 read=160807
I/O Timings: read=639.797
-> Partial GroupAggregate (cost=0.11..479687.58 rows=905 width=12) (actual time=15.779..5026.094 rows=914 loops=2)
Group Key: device_id
Buffers: shared hit=509502 read=160807
I/O Timings: read=639.797
-> Parallel Index Only Scan using index_plots_time_and_device_id on plots (cost=0.11..454158.41 rows=25526447 width=12) (actual time=0.033..2999.764 rows=21697480 loops=2)
Heap Fetches: 0
Buffers: shared hit=509502 read=160807
I/O Timings: read=639.797
Planning Time: 0.092 ms
Execution Time: 7554.100 ms
(19 rows)
您可以尝试将UNIQUE
删除到数据库的索引中。 CREATE UNIQUE INDEX
和CREATE INDEX
具有不同的行为。我相信您可以从CREATE INDEX
中受益。
您可以创建实例化视图。如果您的信息出现延迟,可以执行以下操作:
CREATE MATERIALIZED VIEW myreport AS
SELECT device_id,
MIN(time) AS mintime
FROM plots
GROUP BY device_id
CREATE INDEX myreport_device_id ON myreport(device_id);
此外,您需要记住要定期做:
REFRESH MATERIALIZED VIEW CONCURRENTLY myreport;
并且较少定期这样做:
VACUUM ANALYZE myreport