强制索引扫描以进行多列比较

时间:2019-04-10 16:33:17

标签: sql postgresql indexing

我知道内部索引是B树或类似的树结构。 假设索引是为3列(a,b,c)构建的,我希望Postgres:

  1. 在该B树中找到键[a = 10,b = 20,c = 30]
  2. 扫描下10个条目并返回它们。

如果索引只有一列,则解决方法很明显:

select * from table1
where a >= 10
order by a limit 10

但是,如果有更多列,解决方案将变得更加复杂。对于2列:

select * from table1
where a > 10 or (a = 10 and b >= 20)
order by a, b limit 10

3列:

select * from table1
where a > 10 or (a = 10 and (b > 20 or b = 20 and c >= 30))
order by a, b, c limit 10

请注意查询:

select * from table1
where a >= 10 and b >= 20 and c >= 30
order by a, b, c limit 10

不正确,因为它会过滤掉例如[a = 11,b = 10,c = 1]。

如何告诉Postgres我想要此操作?

我是否可以确定,即使对于2+列的那些复杂查询,优化器也会始终理解他应该执行范围扫描?为什么?

1 个答案:

答案 0 :(得分:3)

使用ROW values进行比较:

SELECT *
FROM   table1
WHERE  (a,b,c) >= (10, 20, 30)
ORDER  BY a,b,c
LIMIT  10;

(使用>=来匹配您的代码,尽管您的描述建议使用>。两者都可以。)

(a,b,c)实际上是ROW(a,b,c)的缩写。

是的,Postgres知道可以为此使用匹配的multicolumn B-tree index(与其他RDBMS不同-或我听说过)。

“匹配” 表示所有索引表达式,它们的序列和关联的顺序(ASC | DESC)是相同的-或整个索引的排序顺序行被完全反转,因此Postgres可以以几乎相同的速度向后扫描索引。
对于给定的示例,这些索引匹配:

(a ASC, b ASC, c ASC)
(a DESC, b DESC, c DESC)

但是这些不是

(a ASC, b DESC, c ASC)
(a ASC, c ASC, b ASC)

针对一系列时间戳(两列)优化查询

相关,带有更多说明: