单个索引扫描只能使用查询子句,该子句使用索引的列及其操作符类的操作符,并与 AND
联接。例如,给定索引 (a, b)
,查询条件如 WHERE a = 5 AND b = 6
可以使用索引,但查询如 WHERE a = 5 OR b = 6
无法直接使用索引。
幸运的是,PostgreSQL 能够组合多个索引(包括多次使用同一个索引)来处理无法通过单个索引扫描实现的情况。系统可以在多个索引扫描中形成 AND
和 OR
条件。例如,查询如 WHERE x = 42 OR x = 47 OR x = 53 OR x = 99
可以分解为对索引 x
的四个单独扫描,每个扫描使用一个查询子句。然后将这些扫描的结果通过 OR 运算在一起以生成结果。另一个示例是,如果我们在 x
和 y
上有单独的索引,则查询如 WHERE x = 5 AND y = 6
的一种可能的实现是使用每个索引和适当的查询子句,然后将索引结果通过 AND 运算在一起以识别结果行。
为了组合多个索引,系统扫描每个需要的索引,并在内存中准备一个位图,给出与该索引条件匹配的表行的位置。然后根据查询需要,将位图通过 AND 和 OR 运算在一起。最后,访问并返回实际表行。表行按物理顺序访问,因为这是位图的布局方式;这意味着原始索引的任何顺序都将丢失,因此如果查询具有 ORDER BY
子句,则需要一个单独的排序步骤。出于此原因,并且因为每个额外的索引扫描都会增加时间,所以计划程序有时会选择使用简单的索引扫描,即使可以使用其他可用索引也是如此。
在所有但最简单的应用程序中,都有各种可能会有用的索引组合,并且数据库开发人员必须做出权衡来决定提供哪些索引。有时多列索引是最好的,但有时最好创建单独的索引并依赖索引组合功能。例如,如果你的工作负载包括有时只涉及列 x
的查询,有时只涉及列 y
,有时涉及这两列,你可能会选择在 x
和 y
上创建两个单独的索引,依赖索引组合来处理使用这两列的查询。你也可以在 (x, y)
上创建一个多列索引。此索引通常对于涉及这两列的查询比索引组合更有效,但如 第 11.3 节 中所述,对于只涉及 y
的查询,它几乎毫无用处,因此它不应该成为唯一的索引。多列索引和 y
上的单独索引的组合将很好地发挥作用。对于只涉及 x
的查询,可以使用多列索引,尽管它会更大,因此比仅在 x
上的索引更慢。最后的备选方案是创建所有三个索引,但这可能仅在表被搜索的频率远高于被更新的频率并且所有三种类型的查询都很常见时才合理。如果其中一种类型的查询远不如其他类型常见,你可能只创建最匹配常见类型的两个索引。