PostgreSQL的:为什么此查询不使用我的索引?(PostgreSQL: Why is this

2019-10-19 06:08发布

我在一个数据库(所有的数字和列名组成)上执行此查询:

select * from t where a=1 and b=11 and c!=5 and d<8

吨具有索引:

create index i on t (a,b,c,d)

当我运行“EXPLAIN ANALYZE”,查询执行顺序扫描,大约需要55毫秒来做到这一点。 如果我修改这样的查询:

select * from t where a=1 and b=11 and c=5 and d<8
                                       ^

它使用索引和0.5 ms内完成。 因此,它必须是不等同,对不对? 事实并非如此,因为如果我这样做查询:

select * from t where a=1 and b=11 and c=5 and d!=8
                                               ^

查询仍然使用索引。 但是,如果我试试这个,没有索引:

select * from t where a=1 and b=11 and c<5 and d<8
                                       ^

那么,为什么Postgres的表现的方式是? 这是很奇怪的我。

Answer 1:

正如你已经意识到,这个问题是关系到使用的不是平等的其他运营商。 索引只能最有效地用于其与由等于(加一米范围条件)进行比较的最左边的列。

在您的例子:

create index i on t (a,b,c,d);
where a=1 and b=11 and c!=5 and d<8;

它可以使用索引只对ab有效。 这意味着DB提取相匹配的所有行ab条件,然后检查每个行对剩余的条件。

当在改变滤波器c到平等,它提取(可能)更小的行(仅那些匹配abc ),然后检查针对那些(更少)的行d滤波器。 使用该指数是在这种情况下更有效。

一般而言,PostgreSQL查询规划计算两个选项:(1)使用的索引; (2)做一个SeqScan。 在这两方面,它计算成本值 - 高这是糟糕的是预期的性能。 因此,把具有较小的成本值。 这是如何决定使用索引或没有,也没有固定的阈值。

最后,写了“加一个范围条件”之上。 这意味着,如果你使用的是等号,也为一个单一的范围条件不仅可以使用索引以最有效的方式。

考虑到你在查询一个单一的范围条件,我建议更改索引是这样的:

create index i on t (a,b,d,c);

现在,它可以使用在过滤器abd有效地与索引,只需要对行过滤掉其中c!=5 。 虽然这个指数可以更有效地利用您所查询的是你原来的一个,它并不自动意味着PG将使用它。 这取决于成本估算。 但试试看。

最后,如果这不是快足够多的5使用的是在表达c!=5是恒定的,你可能会考虑部分索引:

 create index i on t (a,b,d)
        where c!=5;

你可以做到这一点与所有其他列也一样,如果你值比较它们是常数。

参考文献:

  • 索引>,<和BETWEEN
  • 索引多个独立的范围条件(不!)


Answer 2:

我会说,它不使用索引的第一个查询,因为指数并不能真正帮助,因为几乎整个表的匹配。 全表扫描在这种情况下更快。 最后两个查询之间的区别是,如果预期的结果大小低于某一阈值的指数大概只能使用。 与精确匹配的查询将使用少于仍然产生少于等于没有选择最有可能产生的结果越少不止一个。

话虽如此,查询优化是一个高度复杂的软件,并经常会产生令人惊讶的结果。



文章来源: PostgreSQL: Why is this query not using my index?