即使时间范围不包含任何记录,多列排序也会破坏查询性能

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,这将不起作用,因为它们并非相互关联。