【发布时间】:2015-06-18 15:14:03
【问题描述】:
我的表有整数列“a”、“b”。 “a”只有少数(10**7)。为了加快速度,我创建了复合索引 (a,b)。我观察到了
select count(*) from tab where a=1;
跑得也快
select count(*) from tab where a=2;
跑得很快,但是
select count(*) from tab where a=1 or a=2;
运行(哦,天哪)慢,同样是这样的
select count(*) from tab;
运行解释解释,快速查询使用
-> Index Only Scan using idx on tab
但是对于慢速查询,使用顺序扫描。
为什么会这样?为什么 Postgresql 后两个查询不使用相同的索引?只是查询计划器的不完善,还是不能使用 Index Only Scan 的更深层次的原因?
【问题讨论】:
-
一个疯狂的猜测:你在 tab.a 上没有(有效的)统计信息,或者 tab.a 的大部分值是 1 或 2。
-
尝试以这种方式更改第二个查询:
select (select count(*) from tab where a=1)+(select count(*) from tab where a=2);,优化器应该对两个子查询使用 IndexOnlyScan。问题是优化器一般不喜欢or条件。 -
@joop 重要吗,有多少个值 1 和 2? (大约有 1 和 2 的 1/10)。如果在 (a,b) 上构建了复合索引,那么无论有多少这样的记录,它都可以加快查询执行速度,所以我希望 Postgre 使用该索引。
-
@Renzo 正如预期的那样,您的查询运行得很快。您可能对复杂的“或”是正确的,但是,我希望至少最后一个 count( * ) 查询使用索引。请注意,迭代所有可能的“a”值并将部分计数()结果相加比直接计数()快得多。这让我感到惊讶,因为这基本上迫使 Postgre 遍历整个复合索引;为什么 Postgre 不自己做呢?我相信,这样的决定不需要“特殊知识”,但需要(大约)总索引大小。
-
@TomasKulich 你是正确的计数(*),但优化器是奇怪的野兽,只尝试有限数量的可能访问计划。也许在 Postgresql 中有一条规则,当查询没有任何条件时,则不考虑索引...
标签: postgresql indexing count composite-index query-planner