↑↓ 选择↵ 打开⌫ 切换范围完整搜索

PG.CENTER 连接 PostgreSQL 文档、百科与生态知识。由 Pigsty 维护。

支持中的版本: 当前版本 (18) / 17 / 16 / 15 / 14
开发中的版本: 19 / 20devel
已结束支持的版本: 13 / 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
预发布版本文档。 PostgreSQL 19beta4 为测试版本,最终发布内容可能有所不同。

11.3. 多列索引 #

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

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

(假设你把 /dev 目录保存在数据库里……)并且经常发出如下查询:

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

那么将 major 和 minor 两列一起建一个索引可能是合适的,例如:

CREATE INDEX test2_mm_idx ON test2 (major, minor);

当前,只有 B-树、GiST、GIN 和 BRIN 索引类型支持多键列索引。能否有多个键列,与索引中能否添加 INCLUDE 列无关。索引最多可以有 32 列,包括 INCLUDE 列。(这个限制在构建 PostgreSQL 时可以修改;参见文件 pg_config_manual.h。)

多列 B-树索引可以用于涉及索引任意列子集的查询条件,但当对前导(最左)列存在约束时,索引效率最高。精确的规则是:对前导列的等值约束,再加上第一个没有等值约束列上的任意不等约束,总会被用来限制被扫描的索引范围。这些列右侧列上的约束会在索引中进行检查,因此总能减少访问表本体的次数,但不一定会减少必须扫描的索引范围。如果 B-树索引扫描能够有效应用跳过扫描优化,那么它在通过反复的索引搜索遍历索引时,会利用每一列约束。这可能减少需要读取的索引部分,即便一个或多个列(位于查询谓词所涉及的最右侧索引列之前)缺少常规的等值约束。跳过扫描的工作方式是内部生成一个动态的等值约束,使其匹配索引列中的每个可能值(不过这只适用于某个列缺少来自查询谓词的等值约束,且生成的约束能够与查询谓词中较后列的约束联合使用时)。

例如,给定一个(x, y) 上的索引和查询条件 WHERE y = 7700,B-树索引扫描可能能够应用跳过扫描优化。这通常发生在查询规划器预计,根据表上现有的索引,针对每个可能的 N 值(或者索引中实际存储的每个 x 值)反复执行 WHERE x = N AND y = 7700 搜索是最快的方法时。一般来说,只有当不同的 x 值很少,以致规划器预计扫描能跳过索引的大部分内容时,才会采用这种方法(因为大多数叶子页都不可能包含相关元组)。如果不同的 x 值很多,那么就必须扫描整个索引,因此在大多数情况下,规划器会更倾向于顺序扫描表而不是使用该索引。

在至少具有一部分来自查询谓词的有用约束的 B-树扫描中,跳过扫描优化也可以被选择性地应用。例如,给定一个(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-树或 GiST 不同,无论查询条件使用的是哪些索引列,GIN 的索引搜索效果都一样。

多列 BRIN 索引可以用于涉及索引任意列子集的查询条件。和 GIN 一样、不同于 B-树或 GiST,无论查询条件使用的是哪些索引列,索引搜索效果都一样。在单个表上使用多个 BRIN 索引,而不是使用一个多列 BRIN 索引的唯一理由,是需要不同的 pages_per_range 存储参数。

当然,每一列都必须配合适合该索引类型的操作符使用;涉及其他操作符的子句不会被考虑。

多列索引应谨慎使用。在大多数情况下,单列索引已经足够,而且更省空间、也更省时间。除非表的使用方式极其程式化,否则超过三列的索引通常不会有帮助。关于不同索引配置优缺点的讨论,还可参见第 11.5 节和第 11.9 节。

报告文档问题

阅读 上游文档. 反馈更正前请先核对 当前版本手册.