2025年9月25日: PostgreSQL 18 发布!
支持的版本: 当前 (18) / 17 / 16 / 15 / 14 / 13
开发版本: devel
不再支持的版本: 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0 / 8.4 / 8.3 / 8.2 / 8.1 / 8.0 / 7.4 / 7.3 / 7.2

11.3. 多列索引 #

可以在表的多个列上定义索引。例如,如果您有一个具有以下形式的表

CREATE TABLE test2 (
  major int,
  minor int,
  name varchar
);

(假设您将您的 /dev 目录存储在数据库中…),并且您经常执行如下查询

SELECT name FROM test2 WHERE major = constant AND minor = constant;

那么,对 majorminor 列一起定义一个索引可能是合适的,例如:

CREATE INDEX test2_mm_idx ON test2 (major, minor);

目前,只有 B-tree、GiST、GIN 和 BRIN 索引类型支持多键列索引。是否存在多个键列与是否可以向索引添加 INCLUDE 列是独立的。索引最多可以有 32 列,包括 INCLUDE 列。(构建 PostgreSQL 时可以更改此限制;请参阅文件 pg_config_manual.h。)

多列 B-tree 索引可以用于涉及索引列的任何子集的查询条件,但当对最左边的列存在等值约束时,该索引效率最高。确切的规则是,最左边列上的等值约束,加上第一个没有等值约束的列上的任何不等值约束,都将始终用于限制需要扫描的索引部分。右侧列上的约束将在索引中进行检查,因此它们总是可以节省对实际表的访问,但它们不一定能减少需要扫描的索引部分。如果 B-tree 索引扫描可以有效应用跳跃扫描优化,那么它将在遍历索引时通过重复的索引搜索来应用每个列约束。这可以减少需要读取的索引部分,即使一个或多个列(在查询谓词中最不显著的索引列之前)缺乏常规的等值约束。跳跃扫描的工作原理是通过内部生成一个动态等值约束,该约束匹配索引列中的每个可能值(但仅在给定一个缺少查询谓词的等值约束的列,并且仅当生成的约束可以与查询谓词中的后续列约束一起使用时)。

例如,给定一个在 (x, y) 上的索引,以及查询条件 WHERE y = 7700,B-tree 索引扫描可能会应用跳跃扫描优化。这通常发生在查询规划器预期对于每个可能的 N 值(或对于表中实际存储的每个 x 值)重复执行 WHERE x = N AND y = 7700 搜索是给定表中可用索引的最快方法时。这种方法通常仅在 x 的不同值非常少的情况下才会被采用,以至于规划器预期扫描将跳过大部分索引(因为其大部分叶子页面可能不包含相关的元组)。如果 x 的不同值很多,那么将需要扫描整个索引,因此在大多数情况下,规划器将优先选择顺序表扫描而不是使用索引。

跳跃扫描优化也可以选择性地应用,在至少包含一些有用查询谓词约束的 B-tree 扫描期间。例如,给定一个在 (a, b, c) 上的索引和查询条件 WHERE a = 5 AND b >= 42 AND c < 77,索引可能需要从 a = 5 和 b = 42 的第一个条目扫描到 a = 5 的最后一个条目。具有 c >= 77 的索引条目永远不需要在表级别进行过滤,但跳过它们在索引内部是否有益可能有所不同。当发生跳跃时,扫描会启动一个新的索引搜索,从当前 a = 5 和 b = N 组的末尾(即,在索引中第一个元组 a = 5 AND b = N AND c >= 77 出现的位置)重新定位到下一组的开头(即,在索引中第一个元组 a = 5 AND b = N + 1 出现的位置)。

多列 GiST 索引可以用于涉及索引列的任何子集的查询条件。其他列上的条件会限制索引返回的条目,但第一列上的条件对于确定需要扫描多少索引非常重要。如果 GiST 索引的第一列只有少量不同的值,即使其他列有许多不同的值,该索引的有效性也会相对较低。

多列 GIN 索引可以用于涉及索引列的任何子集的查询条件。与 B-tree 或 GiST 不同,无论查询条件使用哪个(些)索引列,索引搜索的有效性都是相同的。

多列 BRIN 索引可以用于涉及索引列的任何子集的查询条件。与 GIN 类似,但与 B-tree 或 GiST 不同,无论查询条件使用哪个(些)索引列,索引搜索的有效性都是相同的。在单个表上拥有多个 BRIN 索引而不是一个多列 BRIN 索引的唯一原因是拥有不同的 pages_per_range 存储参数。

当然,每个列都必须使用适合索引类型的运算符;涉及其他运算符的子句将不被考虑。

应谨慎使用多列索引。在大多数情况下,单列索引就足够了,并且可以节省空间和时间。超过三个列的索引除非表的用法非常特殊,否则不太可能有帮助。有关不同索引配置的优缺点的讨论,请参阅 Section 11.5Section 11.9

提交更正

如果您在文档中看到任何不正确、与您对特定功能的经验不符或需要进一步阐明的内容,请使用 此表单 来报告文档问题。