A
和B
的表。我对A
+ B
进行常规查询,因此我在(A,B)
上创建了一个复合索引。组合索引还会完全优化仅对A
的查询吗?我还在
A
上创建了索引,但Postgres仍然仅对A
使用组合索引来查询。如果前面的答案是肯定的,那么我认为这并不重要,但是如果单个A
索引可用,为什么默认情况下为什么要选择复合索引?#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
评论
我试图为此设置一个小测试。但是,在我的情况下,仅当我删除单列索引1时才使用二列索引,而单列索引与创建第一个列无关。有趣的是,如果我首先创建了两列索引,则初始计划将使用位图堆扫描。如果创建了单列索引,则运行查询(使用索引扫描)并删除新创建的索引,涉及两列索引的计划将切换为索引扫描。请参阅有关SQLFiddle的步骤@dezso有趣。每个查询的费用在哪里?
位图索引扫描成本:107.98,43 ms执行时间。索引扫描一栏:费用为8.69,两栏:43.69。执行时间没有明显差异(波动大于两者之间的差异)。
@Luciano可以显示说明分析和查询文本吗?