单索引扫描只能使用查询子句,该子句使用索引的列及其运算符类中的运算符,并以 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
上的索引的四次单独扫描,每次扫描使用一个查询子句。然后对这些扫描的结果进行或运算以生成结果。另一个示例是,如果我们在 x
和 y
上有单独的索引,则类似 WHERE x = 5 AND y = 6
的查询的一种可能的实现是,对每个索引使用适当的查询子句,然后对索引结果进行与运算以识别结果行。
为了组合多个索引,系统会扫描每个需要的索引,并在内存中准备一个 位图,其中给出了报告与该索引条件匹配的表行的位置。然后,按照查询的需要对位图进行与运算和或运算。最后,访问实际的表行并返回它们。表行将按物理顺序进行访问,因为位图就是这样布局的;这意味着将丢失原始索引的任何顺序,因此,如果查询有 ORDER BY
子句,将需要一个单独的排序步骤。正是由于这个原因,并且因为每次附加索引扫描都会增加额外时间,所以规划程序有时候会选择使用简单的索引扫描,即使还可以使用其他附加索引。
在除最简单的应用程序之外的所有应用程序中,各种索引组合都可能有用,而且数据库开发者必须做出权衡决定提供哪些索引。有时,多列索引是最好的,但有时创建单独的索引并依靠组合索引特性会更好。例如,如果你的工作负载包括有时候只涉及列 x
的查询、有时候只涉及列 y
的查询、有时候涉及这两个列的查询,你可能会选择针对 x
和 y
创建两个单独的索引,依靠索引组合处理使用这两个列的查询。你也可以针对 (x, y)
创建一个多列索引。此索引对于涉及这两个列的查询通常会比索引组合更高效,但如第 11.3 节中所述,对于只涉及 y
的查询来说,它几乎毫无用处,因此它不应该成为唯一的索引。多列索引和针对 y
的单独索引的组合可以合理地发挥作用。对于只涉及 x
的查询,可以使用多列索引,尽管它会更大,因此比仅针对 x
的索引更慢。最后一个备选方案是创建所有三个索引,但这种做法可能只在查询表格的次数远多于更新表格的次数并且所有三种类型的查询都很常见的情况下才是合理的。如果一种类型的查询远不如其他类型常见,你可能会满足于仅创建与常见类型最匹配的两个索引。