假设我有一个包含字段AB的表。我对A + B进行常规查询,因此我在(A,B)上创建了一个复合索引。组合索引还会完全优化仅对A的查询吗?

我还在A上创建了索引,但Postgres仍然仅对A使用组合索引来查询。如果前面的答案是肯定的,那么我认为这并不重要,但是如果单个A索引可用,为什么默认情况下为什么要选择复合索引?

评论

我试图为此设置一个小测试。但是,在我的情况下,仅当我删除单列索引1时才使用二列索引,而单列索引与创建第一个列无关。有趣的是,如果我首先创建了两列索引,则初始计划将使用位图堆扫描。如果创建了单列索引,则运行查询(使用索引扫描)并删除新创建的索引,涉及两列索引的计划将切换为索引扫描。请参阅有关SQLFiddle的步骤

@dezso有趣。每个查询的费用在哪里?

位图索引扫描成本:107.98,43 ms执行时间。索引扫描一栏:费用为8.69,两栏:43.69。执行时间没有明显差异(波动大于两者之间的差异)。

@Luciano可以显示说明分析和查询文本吗?

#1 楼

必然是。我们在以下相关问题下进行了详细讨论:

PostgreSQL中索引的工作

空间以MAXALIGN的倍数分配,通常在64位上为8字节。 OS或32位OS上的(很少见的)4个字节。如果不确定,请检查pg_controldata。它还取决于索引列的数据类型(有些需要对齐填充)和实际内容。
例如,两个integer列(每个4个字节)上的索引通常最终与正好等于一个索引上的索引一样大。一个,其中另外4个字节因对齐填充而丢失。
Postgres 13的更新:新的索引重复数据删除对此进行了更改。重复的索引值可以压缩。 (a,b)上的索引通常不会重复,因此从重复数据删除中获得的收益较少。
如果a是唯一列,则重复数据删除不会有太大变化。 (由于MVCC模型的缘故,仍然会有重复的条目,因此添加b仍然会产生较小的影响。)
除此之外,对于查询计划者来说,使用(a,b)上的索引确实没有任何缺点-与仅(a)的索引。而且通常最好是多个查询使用相同的索引。共享时,它(或它的一部分)驻留在(快速)缓存中的机会会增加。
如果您已经在(a,b)上维护了索引,那么仅在(a)上创建另一个索引就没有意义-除非它要小得多。 (b,a)(a)并非如此。请沿第一行中的链接获取更多信息。
从相反的方向来看,当您需要诸如(a,b)上的附加索引时,请考虑将现有索引仅放在(a)上-如果可能的话。通常是不可能的,因为那是PK或UNIQUE约束的索引。从Postgres 11开始,您可能只用b子句将INCLUDE附加到约束定义中就可以了。手册中的详细信息。
或在(b,a)上创建新索引,以仅覆盖b上的查询。仅对于相等条件,btree索引中的索引表达式的顺序无关紧要。但是,当涉及范围条件时,它确实会。请参阅:

多列索引和性能

即使在索引中只包含其他空间,也会在索引中包含其他列,这可能会带来不利影响:

每当更新附加列时,索引现在也需要更新,这可能会增加写入操作的成本并创建更多索引膨胀。
无法在表上进行HOT更新(仅堆元组)

有关HOT更新的更多信息:

更新语句中的冗余数据

如何测量对象大小:

测量PostgreSQL表行的大小


评论


您能否将其扩展为说,如果我在A列上有一个索引,并且需要添加一个复合索引(A,B),那么应该删除索引A?如果重用索引提高了缓存效率,并且(A,B)完全优化了A,那么似乎在A上附加索引将浪费空间并可能减慢速度

– jvans
19年4月2日在17:05

@jvans:通常为true-带有明显的例外和替代方法。我添加了一个段落来解决这个问题。

–欧文·布兰德斯特
19年4月2日在17:32



#2 楼

根据您的问题,您有一个包含字段A和B的表。
如果您的查询是:

SELECT * FROM [YOUR TBL]
WHERE A='XXXX'


Optimizer将选择Composite索引以避免Extract随机访问!

#3 楼

如果只是在谓词中只使用第一个。

如果使用复合键的第一列和复合键的非键列,它将进行扫描。

要欺骗它,您可以像这样伪造谓词,然后创建非关键列:

[A,B]是您的索引,[C]-另一列

要利用索引,您可以这样写:

SELECT
    A,B,C,D,E
FROM 
    test
WHERE
   A=1
AND
   B=B
AND 
   C=3



...如果单个A索引可用,为什么默认情况下它会选择复合索引?


仅当存在一个或两个谓词[A]或[A],[B]时,才使用索引。它不会按[B],[A]或[A],[C]的顺序使用它。为了能够利用带有附加列[C]的索引,您需要通过将谓词排序为[A],[B]和[C]来强制执行索引。

评论


B = B到底能实现什么?我认为您没有实现任何目标,因此我投了反对票,没有任何证据被优化程序忽略

–杰克·道格拉斯(Jack Douglas)
2012年10月24日9:57

B = B实际上与B IS NOT NULL相同,这似乎是不必要的。当然不需要在(a,b)上使用索引。

–欧文·布兰德斯特
2014年5月27日15:05