Postgresql:当 where 子句中缺少索引子集时,多列索引的最佳使用

Postgresql: optimal use of multicolumn-index when subset of index is missing from the where clause

我将使用类似于以下的 where 子句对我的数据库进行查询:

SELECT * FROM table WHERE a = 'string_value' AND b = 'other_string_value' AND t > <timestamp>

较少见:

SELECT * FROM table WHERE a = 'string_value' AND t > <timestamp>

我已经按照该顺序在 a、b 和 t 上创建了一个多列索引。但是,我不确定它是否适合我的第二次不太频繁的查询。

这个索引是对 b 进行索引扫描还是跳过它并立即移动到 t 索引? (老实说,我不确定索引扫描是如何工作的)。我应该只为第二个查询在 a 和 t 上创建第二个多列索引吗?

docs 指出

'the index is most efficient when there are constraints on the leading (leftmost) columns'

但在示例中,它没有突出显示 where 子句中缺少 'b' 相等列的情况。

对于 (a,b,t) 上的 btree 索引,第二个查询的效率会低得多,因为缺少 b 意味着 t 无法有效使用(它仍然可以用作in-index 过滤器,但这远不如用作 start/stop 点那么好)。 (a,t) 上的索引将能够更有效地支持第二个查询。

但这并不意味着您可以创建该索引。索引占用 space 并且必须维护,因此远非免费。只接受第二个查询的 less-than-optimal 计划可能会更好,因为该查询的使用“较少”。另一方面,您确实为此 post 费心了,所以也许“不经常”仍然很常见。因此,您最好只构建额外的索引并花时间担心其他事情。

btree 索引可以被认为是电话簿,按姓氏、名字、中间名排序。您的第一个查询就像搜索“名为 Mary Smith 且中间名小于 Cathy 的人”您可以使用二进制搜索有效地找到第一个“Mary Smith”,然后扫描这些直到中间名 > 'Cathy',你就完成了。将其与“姓史密斯且中间名小于凯茜的人”进行比较。现在你必须扫描所有的史密斯。您不能停在第一个中间名 > Cathy,因为名字的任何更改都会重置中间名的顺序。

鉴于 b 只有 10 个不同的值,您可以想象在跳过扫描中非常有效地使用 (a,b,t) 索引。但是 PostgreSQL 还没有在本地实现跳过扫描。你可以模仿它们,但那是脆弱的、丑陋的、大量的工作,而且很容易搞砸。你在这里所说的一切都让我觉得这样做是值得的。