所以我第一次使用postgres并发现运行不同并且按查询分组相当慢,目前我正在尝试查找最新记录以及它是否正常工作。 这是我提出的第一个查询:
SELECT DISTINCT ON (device_id) c.device_id, c.timestamp, c.working
FROM call_logs c
ORDER BY c.device_id, c.timestamp desc
它有效,但需要时间来运行。
Unique (cost=94840.24..97370.54 rows=11 width=17) (actual time=424.424..556.253 rows=13 loops=1)
-> Sort (cost=94840.24..96105.39 rows=506061 width=17) (actual time=424.423..531.905 rows=506061 loops=1)
Sort Key: device_id, "timestamp" DESC
Sort Method: external merge Disk: 13272kB
-> Seq Scan on call_logs c (cost=0.00..36512.61 rows=506061 width=17) (actual time=0.059..162.932 rows=506061 loops=1)
Planning time: 0.152 ms
Execution time: 557.957 ms
(7 rows)
我已更新查询以使用以下更快但非常难看的内容:
SELECT c.device_id, c.timestamp, c.working FROM call_logs c
INNER JOIN (SELECT c.device_id, MAX(c.timestamp) AS timestamp
FROM call_logs c
GROUP BY c.device_id)
newest on newest.timestamp = c.timestamp
和分析:
Nested Loop (cost=39043.34..39136.08 rows=12 width=17) (actual time=216.406..216.580 rows=15 loops=1)
-> HashAggregate (cost=39042.91..39043.02 rows=11 width=16) (actual time=216.347..216.351 rows=13 loops=1)
Group Key: c_1.device_id
-> Seq Scan on call_logs c_1 (cost=0.00..36512.61 rows=506061 width=16) (actual time=0.026..125.482 rows=506061 loops=1)
-> Index Scan using call_logs_timestamp on call_logs c (cost=0.42..8.44 rows=1 width=17) (actual time=0.016..0.016 rows=1 loops=13)
Index Cond: ("timestamp" = (max(c_1."timestamp")))
Planning time: 0.318 ms
Execution time: 216.631 ms
(8 rows)
即使200ms对我来说似乎有点慢,因为我想要的只是每台设备的最高记录(在索引表中)
这是我正在使用的索引:
CREATE INDEX call_logs_timestamp
ON public.call_logs USING btree
(timestamp)
TABLESPACE pg_default;
我已尝试过以下索引,但根本没有帮助:
CREATE INDEX dev_ts_1
ON public.call_logs USING btree
(device_id, timestamp DESC, working)
TABLESPACE pg_default;
任何想法我都错过了一些明显的东西吗?
答案 0 :(得分:1)
200 ms对于通过500k行来说真的不是那么糟糕。但是对于这个查询:
SELECT DISTINCT ON (device_id) c.device_id, c.timestamp, c.working
FROM call_logs c
ORDER BY c.device_id, c.timestamp desc
然后call_logs(device_id, timestamp desc, working)
上的索引应该是最佳索引。
为同一索引编写查询的另外两种方法是:
select c.*
from (select c.device_id, c.timestamp, c.working, c.*,
row_number() over (partition by device_id order by timestamp desc) as seqnum
from call_logs c
) c
where seqnum = 1;
和
select c.device_id, c.timestamp, c.working
from call_logs c
where not exists (select 1
from call_logs c2
where c2.device_id = c.device_id and
c2.timestamp > c.timestamp
);