为什么Postgres在简单的ORDER BY LIMIT 1中没有使用我的索引?

13

我有一个大表格(约1100万行),我需要根据排序条件找到第一个项目。

请注意,列Date不接受空值。

为什么Postgres没有使用索引:

CREATE INDEX track_ix_date
  ON "Track"
  USING btree
  ("Date" DESC NULLS LAST);

在这个简单的查询中:

select * from "Track" order by "Date" desc limit 1

但它确实在另一个查询中使用了它:

select * from "Track" order by "Date" desc nulls last limit 1

第二个查询实际上比第一个查询快得多。

我已经阅读了索引和ORDER BY文档,并且指出在具有LIMIT子句的ORDER BY的特殊情况下,使用索引而不是扫描表格要高效得多,因为排序需要扫描整个表格才能获取单个项目。

既然该列不接受null值,Postgres不应该检测到nulls last / first无关紧要并只使用最快的方法吗?


如果您知道您的“DATE”列是“NOT NULL”,为什么还要指定“NULLS LAST”呢? - Nick
因为我注意到索引扫描正在使用条件“DATE IS NOT NULL”,所以我加上了“NULLS LAST”,认为PostgreSQL正在检查该条件,因为在降序排序时,第一个元素被视为可能为空。 - Rafael
1
请编辑您的问题并添加使用explain(analyze,verbose)生成的执行计划。请使用格式化文本,不要使用屏幕截图。 - user330315
3个回答

4

总是需要权衡取舍,因为让优化器更聪明也意味着让优化器变慢,这会对所有人造成影响。

目前,它还不够聪明,所以您需要更改索引定义或查询以使其正常工作。

也许值得在pgsql-hackers邮件列表上请求此类改进,或者自己编写补丁并提交。


1
由于您正在使用该查询进行“选择所有行”,因此Postgres不会使用索引。
我敢打赌,如果您添加了一个“WHERE date =?”条件,索引将被使用。

不行,即使我们添加了 where date = ?,它也没有使用索引。 - Surya

1

我在寻找类似问题的答案时遇到了这个问题。 我在 PostgreSQL 文档中的这篇文章中找到了答案。https://www.postgresql.org/docs/current/indexes-ordering.html

简而言之:Limit N 是一个排序函数。 当查询的 order by 子句有匹配索引时,它可以使用它,否则不能。 所以通过指定 "null last",您将查询的 order by 与索引的顺序匹配,使其可用。 否则,服务器无法确定它是否正在获取正确的 N 条记录。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接