我有一个表,其中包含 BIGSERIAL 类型的“id”列。我也有这一列的索引(降序排序、BTREE、唯一)。
我经常需要从包含数百万条目的表中检索最后 10、20、30 个条目,如下所示:
SELECT * FROM table ORDER BY id DESC LIMIT 10
我本以为这是一个非常清楚的情况:这个特定字段有一个索引,排序顺序匹配,与整个表中的数百万个条目相比,我只需要 10 个条目,这个查询肯定使用索引扫描。
但它不会对整个表进行顺序扫描。
我尝试深入挖掘,没有发现任何异常。 Postgres 文档位于https://www.postgresql.org/docs/9.6/static/indexes-ordering.html https://www.postgresql.org/docs/9.6/static/indexes-ordering.html says:
一个重要的特殊情况是 ORDER BY 与 LIMIT n 的组合:
显式排序必须处理所有数据才能识别第一个
n 行,但如果存在与 ORDER BY 匹配的索引,则前 n
可以直接检索行,而根本不需要扫描其余部分。
但还是不行。有人给我指点吗?也许我只是不再只见树木不见阿甘了……:-(
好吧,大声说出来并试图收集更多信息来提出我的问题显然让我再次看到了阿甘,我发现了真正的问题。我上面提到的文档的下面是这句话:
以升序存储且空值在前的索引可以满足以下任一条件
ORDER BY x ASC NULLS FIRST 或 ORDER BY x DESC NULLS LAST 取决于
扫描的方向。
这就是问题所在。我在索引中指定了排序顺序,但忽略了 NULLS FIRST 与 LAST。
如果您没有在查询中明确提及,Postgres 默认值为 NULLS FIRST。所以 Postgres 发现的是组合 ORDER BY DESC NULLS FIRST ,它没有被我的索引覆盖。 SORT ORDER 和 NULLS 的组合才是重要的。
2种可能的解决方案:
- 在查询中相应地提及 NULLS FIRST/LAST 以便它与索引匹配
- ...或者将索引更改为 NULLS FIRST (这就是我所做的)
现在 Postgres 正在执行适当的索引扫描,并且在查询期间仅触及 10 个元素,而不是全部。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)