11.4. 组合多个索引

一个单独的索引扫描只能使用那些索引字段和对应索引操作符表里面的操作符的查询子句, 以及用 AND 连接的这样的子句。比如,如果我们有一个在 (a, b) 上的索引,一个类似 WHERE a = 5 AND b = 6 的条件可以使用索引, 但是像 WHERE a = 5 OR b = 6 这样的就不能直接使用索引。

从版本 8.1 开始,PostgreSQL 拥有了组合多个索引(包括同一个索引的多次使用), 来处理单个索引扫描不能实现的场合。系统可以在多个索引扫描之间组成 ANDOR 条件。 比如,一个类似 WHERE x = 42 OR x = 47 OR x = 53 OR x = 99 这样的查询可以分解成四个独立的,在 x 上的扫描, 每个扫描使用一个查询子句。然后这些扫描的结果就 OR 在一起,生成结果。 另外一个例子是,如果我们在 xy 上有独立的索引, 一个类似 WHERE x = 5 AND y = 6 这样的查询的可能的实现是使用合适的查询子句使用独立的索引, 然后把索引结果 AND 在一起生成结果行。

为了组合多个索引,系统扫描每个需要的索引,然后在内存里组织一个 bitmap, 它给出索引扫描中报告出来的符合索引条件的表数据行的位置。然后,根据查询的需要, 把这个位图进行 AND 和 OR 在一起。最后,访问实际的表然后检索并返回数据行。 表的数据行是按照物理顺序进行反问的,因为那就是位图的布局; 这就意味着任何原来的索引的排序都将消失,而如果查询有一个 ORDER BY 子句, 那么还会有一个额外的排序步骤。因为这个原因,以及每个额外的索引扫描都增加了额外的时间, 规划器有时候会选择使用简单的索引扫描,即使有多个索引可用也如此。

在大多数最简单的应用里,可能有多种索引的组合可能都是有用的,而数据库开发人员必须在实用哪个索引之间作出平衡。 有时候多字段索引是最好的,但是有时候创建一个独立的索引,然后依靠索引组合特性是更好的。 比如,假如你的查询有时候只涉及字段 x,有时候只涉及字段 y, 有时候两个字段都有,那么你可能会选择创建两个独立的索引在 xy 上, 然后依靠索引组合来处理实用两个字段的查询。你也可以在 (x, y) 上创建一个多字段索引。 这个索引在涉及两个字段的查询里面,通常会比索引组合更高效一些, 但是,正如我们在 Section 11.3 里面讨论的, 它对那些只包含 y 的查询几乎没有用,因此它不能是唯一的一个索引。 一个多字段索引和 y 上的独立索引可能会跑得很好。 因为对那些只涉及 x 的查询,可以实用多字段索引,但是它会更大,因此也比只在 x 上的索引更慢。最后一个选择是创建三个索引,但是这种方法只有在表的更新远比查询少得多, 并且所有三种查询都很普遍的情况下才是合理的。 如果其中一种查询比其它的少很多,那么你可能更愿意只是创建两种匹配更普遍的查询的索引。