11.5. 组合多个索引

一个单独的索引扫描只能用于这样的条件子句:使用被索引字段和索引操作符类中操作符,并且这些条件以 AND连接。 假设在(a, b)上有一个索引,那么类似 WHERE a = 5 AND b = 6 的条件可以使用索引, 但是像WHERE a = 5 OR b = 6的条件就不能直接使用索引。

幸运的是,PostgreSQL能够组合多个索引(包括同一索引的多次使用)来处理单个索引扫描不能实现的情况。 系统可以在多个索引扫描之间组成ANDOR条件。 比如,一个类似WHERE x = 42 OR x = 47 OR x = 53 OR x = 99这样的查询可以分解成四个在x上的独立扫描, 每个扫描使用一个条件,最后将这些扫描的结果OR在一起,生成最终结果。 另外一个例子是,如果我们在xy上有独立的索引,一个类似WHERE x = 5 AND y = 6这样的查询可以分解为几个使用独立索引的子句, 然后把这几个结果AND在一起,生成最终结果。

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

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