我有一個包含 2600 萬條記錄的相當小的表。
CREATE TABLE t1
(
cam varchar(100) NOT NULL,
updatedat timestamp,
objid varchar(40) NOT NULL,
image varchar(100) NOT NULL,
reader varchar(60) NOT NULL,
imgcap timestamp NOT NULL
);
ALTER TABLE t1
ADD CONSTRAINT t1_pk
PRIMARY KEY (reader, cam, image, objid, imgcap);
我有一個簡單的查詢來迭代時間范圍之間的記錄。
SELECT * FROM t1
WHERE updatedat >= '2021-12-09 20:30:00' and updatedat <= '2021-12-09 20:32:01'
ORDER BY reader ASC , imgcap ASC, objid ASC, cam ASC, image ASC
LIMIT 10000
OFFSET 0;
我添加了一個索引來支持查詢,比較作為最左邊的欄位,其余元素支持排序。
CREATE INDEX t1_idtmp ON t1 USING btree (updatedat , reader , imgcap , objid, cam, image);
但是,查詢需要 10 多秒才能完成。即使范圍內沒有元素也需要相同的時間。
-> Incremental Sort (cost=8.28..3809579.24 rows=706729 width=223) (actual time=11034.114..11065.710 rows=10000 loops=1)
Sort Key: reader, imgcap, objid, cam, image
Presorted Key: reader, imgcap
Full-sort Groups: 62 Sort Method: quicksort Average Memory: 42kB Peak Memory: 42kB
Pre-sorted Groups: 62 Sort Methods: top-N heapsort, quicksort Average Memory: 58kB Peak Memory: 58kB
-> Index Scan using t1_idxevtim on t1 (cost=0.56..3784154.75 rows=706729 width=223) (actual time=11033.613..11036.823 rows=10129 loops=1)
Filter: ((updatedat >= '2021-12-09 20:30:00'::timestamp without time zone) AND (updatedat <= '2021-12-09 20:32:01'::timestamp without time zone))
Rows Removed by Filter: 25415461
Planning Time: 0.137 ms
Execution Time: 11066.791 ms
表上還有更多索引來支持其他用例。
CREATE INDEX t1_idxua ON t1 USING btree (updatedat);
CREATE INDEX t1_idxevtim ON t1 USING btree (reader, imgcap);
我認為,Postgresql 希望避免昂貴的排序,并認為預排序的鍵會更快,但為什么 Postgresql 不使用 t1_idtmp 索引,因為搜索和排序都可以滿足它?
uj5u.com熱心網友回復:
為什么 Postgresql 不使用 t1_idtmp 索引,因為搜索和排序都可以滿足它?
因為排序不能滿足它。一個 btree 索引(updatedat , reader , imgcap , objid, cam, image)只能產生reader , imgcap , objid, cam, image在 updateat 關系內按for排序的資料。因此,如果您的條件適用于特定的 updateat 值,那將起作用。但由于它是針對一系列 updateat,這將不起作用,因為它們并非全部相互關聯。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/380416.html
