单个索引扫描只能使用查询子句,这些子句使用索引的列,并带有限定符类中的操作符,并且通过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
的查询用处较小。其有用程度取决于B-tree索引跳过扫描优化有多有效;如果x
只有几百个不同的值,跳过扫描将使搜索特定y
值的操作执行得相当高效。在(x, y)
上的多列索引和y
上的单独索引的组合也可能效果不错。对于仅涉及x
的查询,可以使用多列索引,尽管它会比仅在x
上的索引更大,因此也更慢。最后一个选择是创建所有三个索引,但这可能只在表被搜索的频率远高于其被更新的频率,并且这三种类型的查询都很常见时才合理。如果其中一种查询类型比其他类型少见得多,你可能会选择只创建最符合常见类型的两个索引。
如果你在文档中发现任何不正确的内容,与你对特定功能的实际体验不符,或者需要进一步澄清,请使用此表单报告文档问题。