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 还没有在本地实现跳过扫描。你可以模仿它们,但那是脆弱的、丑陋的、大量的工作,而且很容易搞砸。你在这里所说的一切都让我觉得这样做是值得的。
我将使用类似于以下的 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 还没有在本地实现跳过扫描。你可以模仿它们,但那是脆弱的、丑陋的、大量的工作,而且很容易搞砸。你在这里所说的一切都让我觉得这样做是值得的。