Postgresql Postgres查询速度慢,仅扫描索引
我有一个表call\u logs,它包含一个id、device\u id、timestamp变量以及一些其他字段。 我目前正在尝试编写一个查询,如果它对每个设备都有效,则返回最后一个调用。 目前我的查询是:Postgresql Postgres查询速度慢,仅扫描索引,postgresql,Postgresql,我有一个表call\u logs,它包含一个id、device\u id、timestamp变量以及一些其他字段。 我目前正在尝试编写一个查询,如果它对每个设备都有效,则返回最后一个调用。 目前我的查询是: SELECT DISTINCT ON (device_id) c.device_id, c.timestamp, c.working, c.id FROM call_logs c ORDER BY c.device_id, c.timestamp desc; 它会返回我想要的信息。 但我的
SELECT DISTINCT ON (device_id) c.device_id, c.timestamp, c.working, c.id
FROM call_logs c
ORDER BY c.device_id, c.timestamp desc;
它会返回我想要的信息。
但我的生产服务器现在变得相当大,表中有大约6000000条记录
我在此表中添加了一个索引:
CREATE INDEX cl_device_timestamp
ON public.call_logs USING btree
(device_id, timestamp DESC, id, working)
TABLESPACE pg_default;
但是我得到了我认为很慢的时间:
以下是对该问题的解释和分析:
EXPLAIN ANALYSE SELECT DISTINCT ON (device_id) c.device_id, c.timestamp, c.working, c.id
FROM call_logs c
ORDER BY c.device_id, c.timestamp desc;
QUERY PLAN
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
Unique (cost=0.56..363803.37 rows=120 width=25) (actual time=0.069..2171.201 rows=124 loops=1)
-> Index Only Scan using cl_device_timestamp on call_logs c (cost=0.56..347982.87 rows=6328197 width=25) (actual time=0.067..1594.953 rows=6331024 loops=1)
Heap Fetches: 8051
Planning time: 0.184 ms
Execution time: 2171.281 ms
(5 rows)
我只有124个唯一的设备id。我不会想到这将是一个索引的缓慢过程?你知道怎么回事吗?或者为什么这么慢?您的索引位于4列,而不是一列。您无法基于四列数据分布中的一列来估计复合索引的大小和效率 下一步-只有124个不同的设备并不意味着索引速度更快。相反-不太明显的值将树拆分为更小的部分,因此部分更大。例如,一百万个bigint值上的bigserial有一百万个不同的值,并且准确的id很快就得到了。而布尔列索引扫描只有两(三)个值,因此需要更长的时间 最后一个参数-两秒钟确实很慢。但是考虑到你扫描了600万行,比较时间戳,我认为2秒是可以接受的 您可以牺牲OLTP速度,创建一些触发器,将每个设备的数据更改的最后时间戳等对保存到某个外部表中。然后,对于127个设备,从短外部表中选择这样的预聚合值需要几微秒的时间 我最后做了这样一件事:
SELECT DISTINCT d.id, c.timestamp, c.id, c.working
FROM devices d
INNER JOIN call_logs c on d.id = c.device_id AND c.timestamp = (SELECT max(t.timestamp) FROM call_logs t WHERE t.device_id = d.id)
结果好多了
Unique (cost=607.92..608.06 rows=11 width=25) (actual time=3.291..3.344 rows=117 loops=1)
-> Sort (cost=607.92..607.95 rows=11 width=25) (actual time=3.289..3.310 rows=117 loops=1)
Sort Key: d.id, c."timestamp", c.id, c.working
Sort Method: quicksort Memory: 34kB
-> Nested Loop (cost=1.05..607.73 rows=11 width=25) (actual time=0.057..3.162 rows=117 loops=1)
-> Seq Scan on devices d (cost=0.00..4.18 rows=118 width=8) (actual time=0.006..0.029 rows=119 loops=1)
-> Index Only Scan using cl_device_timestamp on call_logs c (cost=1.05..5.10 rows=1 width=25) (actual time=0.007..0.007 rows=1 loops=119)
Index Cond: ((device_id = d.id) AND ("timestamp" = (SubPlan 2)))
Heap Fetches: 110
SubPlan 2
-> Result (cost=0.48..0.49 rows=1 width=8) (actual time=0.018..0.018 rows=1 loops=119)
InitPlan 1 (returns $1)
-> Limit (cost=0.43..0.48 rows=1 width=8) (actual time=0.017..0.017 rows=1 loops=119)
-> Index Only Scan Backward using test1 on call_logs t (cost=0.43..2674.01 rows=52483 width=8) (actual time=0.017..0.017 rows=1 loops=119)
Index Cond: ((device_id = d.id) AND ("timestamp" IS NOT NULL))
Heap Fetches: 110
Planning time: 0.645 ms
Execution time: 3.461 ms
(18 rows)
如果删除
不同的
,执行时间如何?如果你只想打最后一个电话,你不能添加LIMIT 1
并使DISTINCT
变得不必要吗?尽量避免DISTINCT,请参见:但是LIMIT 1只给我1个设备,每个设备需要1个