即使时间范围不包含任何记录,多列排序也会破坏查询性能
Multi column order by kills query performance even when the time range does not contain any records
我只有 2600 万条记录table。
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
);</pre>
ALTER TABLE t1
ADD CONSTRAINT t1_pk
PRIMARY KEY (reader, cam, image, objid, imgcap);</pre>
我有一个简单的查询来迭代一个时间范围内的记录。
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);</pre>
但是,查询需要 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
table 上还有几个索引可以支持其他用例。
CREATE INDEX t1_idxua ON t1 USING btree (updatedat);</pre>
CREATE INDEX t1_idxevtim ON t1 USING btree (reader, imgcap);</pre>
我认为,Postgresql 想避免昂贵的排序,并认为预排序键会更快,但为什么 Postgresql 不使用 t1_idtmp 索引,因为搜索和排序都可以满足它?
why does Postgresql not use the t1_idtmp index as both search & sort can be satisfied with it?
因为它不能满足排序。 (updatedat , reader , imgcap , objid, cam, image)
上的 btree 索引只能在 updatedat 的关系内生成按 reader , imgcap , objid, cam, image
排序的数据。因此,如果您的条件是特定的 updatedat 值,那将起作用。但由于它是针对一系列 updatedat,这将不起作用,因为它们并非相互关联。
我只有 2600 万条记录table。
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 );</pre>
ALTER TABLE t1 ADD CONSTRAINT t1_pk PRIMARY KEY (reader, cam, image, objid, imgcap);</pre>
我有一个简单的查询来迭代一个时间范围内的记录。
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);</pre>
但是,查询需要 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
table 上还有几个索引可以支持其他用例。
CREATE INDEX t1_idxua ON t1 USING btree (updatedat);</pre>
CREATE INDEX t1_idxevtim ON t1 USING btree (reader, imgcap);</pre>
我认为,Postgresql 想避免昂贵的排序,并认为预排序键会更快,但为什么 Postgresql 不使用 t1_idtmp 索引,因为搜索和排序都可以满足它?
why does Postgresql not use the t1_idtmp index as both search & sort can be satisfied with it?
因为它不能满足排序。 (updatedat , reader , imgcap , objid, cam, image)
上的 btree 索引只能在 updatedat 的关系内生成按 reader , imgcap , objid, cam, image
排序的数据。因此,如果您的条件是特定的 updatedat 值,那将起作用。但由于它是针对一系列 updatedat,这将不起作用,因为它们并非相互关联。