为什么主键上的 "order by" 会更改查询计划以使其忽略有用的索引?

Why is "order by" on the primary key changing the query plan so that it ignores an useful index?

在调查了为什么多列索引在我期望的情况下没有帮助加快查询速度之后,我意识到这是因为一个简单的 ORDER BY 子句。

我将查询简化为这种简单的形式(首先没有 ORDER BY,然后有):

somedb=# explain select * from user_resource where resource_id = 943 and status = 2 limit 10;
                                                    QUERY PLAN                                                     
-------------------------------------------------------------------------------------------------------------------
 Limit  (cost=0.56..39.29 rows=10 width=44)
   ->  Index Scan using user_resource_resource_id_status on user_resource  (cost=0.56..5422.22 rows=1400 width=44)
         Index Cond: ((resource_id = 943) AND (status = 2))
(3 rows)

Time: 0.409 ms
somedb=# explain select * from user_resource where resource_id = 943 and status = 2 order by id desc limit 10;
                                                          QUERY PLAN                                                          
------------------------------------------------------------------------------------------------------------------------------
 Limit  (cost=1000.46..4984.60 rows=10 width=44)
   ->  Gather Merge  (cost=1000.46..558780.31 rows=1400 width=44)
         Workers Planned: 2
         ->  Parallel Index Scan Backward using idx_121518_primary on user_resource  (cost=0.44..557618.69 rows=583 width=44)
               Filter: ((resource_id = 943) AND (status = 2))

添加 ORDER BY 后,您可以看到 user_resource_resource_id_status 键不再使用,查询速度变慢约 10 倍。

这是为什么?有没有办法解决它?我认为按一个简单的整数字段排序不应该使索引变得无用。谢谢。

这取决于您创建 index 的方式。示例 NULLS FIRSTASC, DESC, NULLS FIRST, and/or NULLS LAST

参考 https://www.postgresql.org/docs/current/indexes-ordering.html,解释如何使用 Indexes and ORDER BY

limit有关。

您可以运行不带限制子句且偏移量为 0 的查询以防止内联子查询,然后应用限制。

select * from (
   select * from user_resource 
   where resource_id = 943 
      and status = 2
   offset 0
) sub
 order by id desc 
limit 10;