【问题标题】:Multicolumn index for where and order by clause (postgres)where 和 order by 子句的多列索引(postgres)
【发布时间】:2021-07-06 18:07:06
【问题描述】:

考虑这样的查询:

select ... from table where a = 1 and b > 2 order by c asc

这个查询的理想索引是什么? 我应该使用一个索引(a,b,c)还是两个单独的(a,b)和(c)?

提前致谢。

【问题讨论】:

  • 这取决于数据的统计和选择了多少行。但是,我希望 (a, b) 在许多情况下都是最佳的。
  • @GordonLinoff 但是排序也应该从索引中受益......第二个条件'>'会破坏索引扫描吗?
  • 。 .当where 子句中存在不等式时,使用索引进行排序有时会很棘手。

标签: sql postgresql indexing


【解决方案1】:

你可能不能同时做好。相等不是问题,但你不能干净地将不等与排序结合起来。您希望返回多少行?如果b>2 非常有选择性,只剩下几行要排序,那么显然你想要(a,b),因为获得选择性很有用,而对剩余的几行进行排序不会花费很长时间。另一方面,如果b>2 只排除几行,那么(a,c)(可能在末尾有更多列以允许仅索引扫描)避免了大的慢排序,同时删除了少数失败的行b“艰难的道路”并不需要很长时间。

您可以同时构建两者并让规划者进行调用,尽管这样做远非完美。

可以在所有三个列上使用 GiST 索引来同时实现不等式过滤和排序,但 GiST 索引的开销比 BTree 索引高得多,而且构建和维护速度也较慢,因此它是不太可能值得,尽管如果您使用 LIMIT 可以使其更具吸引力。您还需要以扭曲的方式编写查询,作为 KNN 查询(​​由 btree_gist 扩展名辅助):

where a = 1 and b > 2 order by c <-> impossibly_low_value

还有其他高级可能性。如果你比较 b 的对象总是&gt;2,那么你可以使用部分索引(a,c) where b&gt;2 或表达式索引(a,(b&gt;2),c)。您也许还可以在 b 上进行有用的分区。如果 b 有少量不同的值,您可以对每个合格的不同值的查询结果进行 UNION 并使用(a,b,c) 上的索引,从而获得有效的合并追加:

(select * from foo where a=1 and b=3 order by c asc) 
    union all 
(select * from foo where a=1 and b=4 order by c asc) 
order by c asc;

【讨论】:

  • UNION 方法真的有助于排序吗?
  • 应该是 UNION ALL,而不仅仅是 UNION。它通过保留索引顺序来提供顺序而根本不进行排序。它的有效性取决于表的集群程度,以及顺序与随机页面成本。当然,当指定一个 LIMIT 时,效果最为明显。
  • 我的意思是,如果你得到两个排序结果(使用索引)然后UNION ALL 他们,结果必须再次排序(就像你在答案中所做的那样)。但是你不妨在子查询中省略ORDER BY,索引将不会用于对整体结果进行排序。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-01
  • 1970-01-01
  • 2016-06-12
  • 1970-01-01
相关资源
最近更新 更多