为啥主键上的“order by”会更改查询计划,从而忽略有用的索引?
Posted
技术标签:
【中文标题】为啥主键上的“order by”会更改查询计划,从而忽略有用的索引?【英文标题】:Why is "order by" on the primary key changing the query plan so that it ignores an useful index?为什么主键上的“order by”会更改查询计划,从而忽略有用的索引? 【发布时间】:2020-07-28 12:06:10 【问题描述】:在调查了为什么多列索引无法像我预期的那样加快查询速度后,我意识到这是因为一个简单的 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 倍。
这是为什么?有没有办法解决它?我认为按一个简单的整数字段排序不应该使索引无用。谢谢。
【问题讨论】:
【参考方案1】:与limit
相关。
您可以在没有限制子句且偏移量为 0 的情况下运行查询,以防止内联子查询,然后应用限制。
select * from (
select * from user_resource
where resource_id = 943
and status = 2
offset 0
) sub
order by id desc
limit 10;
【讨论】:
如果我删除它使用它的 LIMIT ,真的哇!我没想到会这样,对我来说这是违反直觉的。感谢您的解决方案。不确定我是否可以使用 ORM 轻松地将其调整为我的原始查询。需要这样的嵌套来使用索引似乎很奇怪。 这看起来像是一个糟糕的计划决策 - 计划者应该计算出使用正确的索引 + 排序比按排序顺序遍历索引 + 过滤成本更低,因此它应该选择第一个执行计划。 【参考方案2】:这取决于您如何创建index
。示例NULLS FIRST
、ASC, DESC, NULLS FIRST, and/or NULLS LAST
参考https://www.postgresql.org/docs/current/indexes-ordering.html,解释如何使用Indexes and ORDER BY
【讨论】:
以上是关于为啥主键上的“order by”会更改查询计划,从而忽略有用的索引?的主要内容,如果未能解决你的问题,请参考以下文章