Postgresql 中文操作指南
11.5. Combining Multiple Indexes #
单个索引扫描只能使用查询子句,这些子句使用索引列与其运算符类中的运算符,并与 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 运算找出结果行。
为了合并多个索引,系统将扫描每个所需的索引,并在内存中准备一个 bitmap,给出报告与该索引条件匹配的表行的位置。然后根据需要按位 AND 和按位 OR 运算位图。最后,访问并返回实际的表行。表行按物理顺序访问,因为这就是位图的布局方式;这意味着原始索引的任何顺序都将会丢失,因此如果查询具有 ORDER BY 子句,则需要一个单独的排序步骤。出于此原因,并且由于每个额外的索引扫描都会增加额外的时间,因此计划程序有时会选择使用简单的索引扫描,即使可以同时使用其他可用索引。
除了最简单的应用程序外,还有可能会有各种有用的索引组合,而数据库开发人员必须权衡做出取舍来决定提供哪些索引。有时多列索引最好,但有时最好创建单独的索引并依靠索引组合功能。例如,如果你的工作负载包含有时仅涉及列 x、有时仅涉及列 y、有时同时涉及这两个列的查询的混合,则你可能选择在 _x_和 _y_上创建两个单独的索引,同时依赖于索引组合来处理同时使用这两列的查询。你也可以在 _(x, y)_上创建多列索引。这个索引通常比索引组合更高效,适用于涉及这两列的查询,但如 Section 11.3中所述,对于仅涉及 _y_的查询它几乎是无用的,因此它不应该是唯一的索引。多列索引与 _y_上一个单独索引的组合将很好地起到作用。对于仅涉及 _x_的查询,可以使用多列索引,尽管它在体积上会更大和速度会更慢,而仅_x_上的索引则没有这些问题。最后一个备选方案是创建所有三个索引,但这可能仅在表被搜索的频率远远高于其被更新,并且所有三种类型的查询都很常见的情况下才合理。如果其中一种类型的查询的常见程度远低于其他类型,则你可能将满足于仅创建与最常见的类型最匹配的两个索引。