支持的版本: 当前 (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 / 7.1

CREATE INDEX

CREATE INDEX — 定义一个新的索引

概要

CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ [ IF NOT EXISTS ] name ] ON [ ONLY ] table_name [ USING method ]
    ( { column_name | ( expression ) } [ COLLATE collation ] [ opclass [ ( opclass_parameter = value [, ... ] ) ] ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
    [ INCLUDE ( column_name [, ...] ) ]
    [ NULLS [ NOT ] DISTINCT ]
    [ WITH ( storage_parameter [= value] [, ... ] ) ]
    [ TABLESPACE tablespace_name ]
    [ WHERE predicate ]

描述

CREATE INDEX 在指定的关系(可以是一个表或一个物化视图)的指定列上构建一个索引。索引主要用于提高数据库性能(尽管不恰当的使用会导致性能下降)。

索引的键字段被指定为列名,或者作为在圆括号中编写的表达式。如果索引方法支持多列索引,则可以指定多个字段。

索引字段可以是从表行的一列或多列值计算出的表达式。此功能可用于基于基本数据的某种转换来快速访问数据。例如,在 upper(col) 上计算的索引将允许子句 WHERE upper(col) = 'JIM' 使用索引。

PostgreSQL 提供了 B 树、哈希、GiST、SP-GiST、GIN 和 BRIN 等索引方法。用户也可以定义自己的索引方法,但这相当复杂。

当存在 WHERE 子句时,将创建一个部分索引。部分索引是一个只包含表中一部分条目的索引,通常是表中比其余部分更有利于索引的一部分。例如,如果你有一个包含已计费和未计费订单的表,其中未计费订单占总表的一小部分,但却是一个经常使用的部分,则可以通过仅在该部分上创建索引来提高性能。另一个可能的应用是使用 WHEREUNIQUE 在表的子集上强制执行唯一性。有关更多讨论,请参见第11.8节

WHERE 子句中使用的表达式只能引用基础表的列,但可以使用所有列,而不仅仅是正在索引的列。目前,子查询和聚合表达式在 WHERE 中也是禁止的。同样的限制也适用于作为表达式的索引字段。

索引定义中使用的所有函数和运算符都必须是不可变的,也就是说,它们的结果必须仅取决于它们的参数,而不是任何外部影响(例如,另一个表的内容或当前时间)。此限制确保了索引的行为是明确定义的。要在索引表达式或 WHERE 子句中使用用户定义的函数,请记住在创建函数时将其标记为不可变。

参数

UNIQUE

导致系统在创建索引时(如果数据已经存在)以及每次添加数据时检查表中的重复值。尝试插入或更新会导致重复条目的数据将生成错误。

当唯一索引应用于分区表时,会施加额外的限制;请参见CREATE TABLE

CONCURRENTLY

当使用此选项时,PostgreSQL 将构建索引,而不会获取任何阻止对表进行并发插入、更新或删除的锁;而标准索引构建会在完成之前锁定对表的写入(但不锁定读取)。使用此选项时需要注意一些警告 — 请参见下面的并发构建索引

对于临时表,CREATE INDEX 始终是非并发的,因为没有其他会话可以访问它们,并且非并发索引创建更便宜。

IF NOT EXISTS

如果已存在同名的关系,则不抛出错误。在这种情况下会发出通知。请注意,不能保证现有索引与将要创建的索引相似。当指定 IF NOT EXISTS 时,索引名称是必需的。

INCLUDE

可选的 INCLUDE 子句指定一个列列表,这些列将作为非键列包含在索引中。非键列不能用于索引扫描搜索条件,并且在索引强制执行的任何唯一性或排除约束中都会被忽略。但是,索引扫描可以返回非键列的内容,而无需访问索引的表,因为它们可以直接从索引条目获得。因此,添加非键列允许索引扫描用于原本不能使用它们的查询。

明智的做法是对向索引添加非键列保持谨慎,特别是宽列。如果索引元组超过索引类型允许的最大大小,则数据插入将失败。无论如何,非键列会复制索引表中的数据,并使索引的大小膨胀,从而可能减慢搜索速度。此外,B 树去重永远不会用于具有非键列的索引。

INCLUDE 子句中列出的列不需要相应的运算符类;该子句可以包含其数据类型没有为给定访问方法定义运算符类的列。

由于表达式不能在仅索引扫描中使用,因此不支持将表达式作为包含的列。

当前,B 树、GiST 和 SP-GiST 索引访问方法支持此功能。在这些索引中,INCLUDE 子句中列出的列的值包含在对应于堆元组的叶子元组中,但不包含在用于树导航的较高层索引条目中。

name

要创建的索引的名称。此处不能包含模式名称;索引始终在其父表所在的模式中创建。索引的名称必须与该模式中的任何其他关系(表、序列、索引、视图、物化视图或外部表)的名称不同。如果省略名称,则 PostgreSQL 会根据父表的名称和索引的列名选择合适的名称。

ONLY

表示如果表是分区的,则不递归创建分区上的索引。默认是递归。

table_name

要索引的表的名称(可能包含模式限定符)。

method

要使用的索引方法的名称。选项包括 btreehashgistspgistginbrin 或用户安装的访问方法,如bloom。默认方法是 btree

column_name

表的列的名称。

expression

基于表的一列或多列的表达式。如语法所示,表达式通常必须用圆括号括起来。但是,如果表达式的形式是函数调用,则可以省略圆括号。

collation

要用于索引的排序规则的名称。默认情况下,索引使用为要索引的列声明的排序规则或要索引的表达式的结果排序规则。具有非默认排序规则的索引对于涉及使用非默认排序规则的表达式的查询很有用。

opclass

运算符类的名称。有关详细信息,请参见下文。

opclass_parameter

运算符类参数的名称。有关详细信息,请参见下文。

ASC

指定升序排序(这是默认值)。

DESC

指定降序排序。

NULLS FIRST

指定空值在非空值之前排序。当指定 DESC 时,这是默认值。

NULLS LAST

指定空值在非空值之后排序。当未指定 DESC 时,这是默认值。

NULLS DISTINCT
NULLS NOT DISTINCT

指定对于唯一索引,空值是否应被视为不同的(不相等)。默认情况下,它们是不同的,因此唯一索引可以在列中包含多个空值。

storage_parameter

特定于索引方法的存储参数的名称。有关详细信息,请参见下面的索引存储参数

tablespace_name

在其中创建索引的表空间。如果未指定,则会查询default_tablespace,或者对于临时表上的索引,会查询 temp_tablespaces

predicate

部分索引的约束表达式。

索引存储参数

可选的 WITH 子句指定索引的存储参数。每种索引方法都有自己的一组允许的存储参数。B 树、哈希、GiST 和 SP-GiST 索引方法都接受此参数

fillfactor (integer) #

索引的填充因子是一个百分比,它决定了索引方法尝试填充索引页的程度。对于 B 树,在初始索引构建期间以及在右侧扩展索引时(添加新的最大键值),叶子页会填充到此百分比。如果页面随后变得完全满,它们将被拆分,从而导致磁盘索引结构的碎片化。B 树使用默认的填充因子 90,但可以选择 10 到 100 之间的任何整数值。

在预计会进行大量插入和/或更新的表上,B 树索引可以在 CREATE INDEX 时使用较低的填充因子设置(在批量加载到表之后)。50 - 90 范围内的值可以有效地平滑 B 树索引早期生命周期中页面拆分的速率(这样降低填充因子甚至可以降低页面拆分的绝对数量,尽管这种效果高度依赖于工作负载)。第 64.1.4.2 节中描述的 B 树自底向上索引删除技术依赖于页面上有一些额外的空间来存储额外的元组版本,因此会受到填充因子的影响(尽管这种影响通常不显著)。

在其他特定情况下,在 CREATE INDEX 时将填充因子增加到 100 可能是有用的,以此来最大化空间利用率。只有当你完全确定表是静态的(即它永远不会受到插入或更新的影响)时,才应该考虑这样做。否则,将填充因子设置为 100 有损害性能的风险:即使是少量的更新或插入也会导致页面拆分突然大量发生。

其他索引方法以不同但大致类似的方式使用填充因子;默认填充因子在各种方法之间有所不同。

B 树索引还接受以下参数

deduplicate_items (boolean) #

控制 第 64.1.4.3 节中描述的 B 树重复数据删除技术的使用。设置为 ONOFF 以启用或禁用优化。(允许使用 第 19.1 节中描述的 ONOFF 的其他拼写)。默认为 ON

注意

通过 ALTER INDEX 关闭 deduplicate_items 会阻止将来的插入触发重复数据删除,但它本身不会使现有的发布列表元组使用标准元组表示。

GiST 索引还接受以下参数

buffering (enum) #

确定是否使用 第 64.2.4.1 节中描述的缓冲构建技术来构建索引。设置为 OFF 时禁用缓冲,设置为 ON 时启用缓冲,设置为 AUTO 时最初禁用缓冲,但一旦索引大小达到 effective_cache_size,就会动态启用缓冲。默认为 AUTO。请注意,如果可以进行排序构建,则除非指定 buffering=ON,否则将使用排序构建而不是缓冲构建。

GIN 索引接受不同的参数

fastupdate (boolean) #

此设置控制 第 64.4.4.1 节中描述的快速更新技术的使用。它是一个布尔参数:ON 启用快速更新,OFF 禁用快速更新。默认为 ON

注意

通过 ALTER INDEX 关闭 fastupdate 会阻止将来的插入进入待处理的索引条目列表,但它本身不会刷新以前的条目。您可能需要在之后 VACUUM 表或调用 gin_clean_pending_list 函数,以确保清空待处理列表。

gin_pending_list_limit (integer) #

自定义 gin_pending_list_limit 参数。此值以千字节为单位指定。

BRIN索引接受不同的参数

pages_per_range (integer) #

定义组成一个块范围的表块的数量,每个块范围对应于BRIN索引的每个条目(有关更多详细信息,请参见第 64.5.1 节)。默认为 128

autosummarize (boolean) #

定义在下一个页面范围上检测到插入时,是否为上一个页面范围排队运行汇总。有关更多详细信息,请参见第 64.5.1.1 节。默认为 off

并发构建索引

创建索引可能会干扰数据库的常规操作。通常,PostgreSQL 会锁定要建立索引的表以防止写入,并使用对表的单次扫描来执行整个索引构建。其他事务仍然可以读取该表,但如果他们尝试在表中插入、更新或删除行,则他们将被阻塞,直到索引构建完成。如果系统是正在运行的生产数据库,这可能会产生严重的影响。非常大的表可能需要数小时才能建立索引,即使对于较小的表,索引构建也可能会将写入器锁定一段时间,这对于生产系统来说是不可接受的。

PostgreSQL 支持在不锁定写入的情况下构建索引。此方法是通过指定 CREATE INDEXCONCURRENTLY 选项来调用的。使用此选项时,PostgreSQL 必须对表执行两次扫描,此外,它必须等待所有可能修改或使用该索引的现有事务终止。因此,此方法需要比标准索引构建更多的工作,并且完成时间明显更长。但是,由于它允许在构建索引时继续正常操作,因此此方法对于在生产环境中添加新索引非常有用。当然,创建索引所施加的额外 CPU 和 I/O 负载可能会减慢其他操作。

在并发索引构建中,实际上在系统目录中以无效索引的形式输入索引,然后另外两个事务中进行两次表扫描。在每次表扫描之前,索引构建必须等待已修改表的现有事务终止。在第二次扫描之后,索引构建必须等待任何具有早于第二次扫描的快照(请参阅第 13 章)的事务终止,包括其他表上任何并发索引构建的任何阶段使用的事务(如果涉及的索引是部分索引或具有非简单列引用的列)。然后,最终可以将索引标记为有效并准备好使用,并且 CREATE INDEX 命令终止。然而,即使这样,索引也可能不会立即用于查询:在最坏的情况下,只要存在早于索引构建开始时间的事务,就无法使用它。

如果在扫描表时出现问题,例如死锁或唯一索引中的唯一性冲突,则 CREATE INDEX 命令将失败,但会留下一个无效的索引。此索引将因可能不完整而被查询忽略;但是,它仍会消耗更新开销。psql \d 命令会将此类索引报告为 INVALID

postgres=# \d tab
       Table "public.tab"
 Column |  Type   | Collation | Nullable | Default
--------+---------+-----------+----------+---------
 col    | integer |           |          |
Indexes:
    "idx" btree (col) INVALID

在这种情况下,建议的恢复方法是删除索引并再次尝试执行 CREATE INDEX CONCURRENTLY。(另一种可能性是使用 REINDEX INDEX CONCURRENTLY 重建索引)。

并发构建唯一索引的另一个注意事项是,当第二次表扫描开始时,唯一性约束已经针对其他事务强制执行。这意味着在索引可供使用之前,甚至在索引构建最终失败的情况下,都可能在其他查询中报告约束冲突。此外,如果第二次扫描中发生故障,则无效的索引会继续强制执行其唯一性约束。

支持并发构建表达式索引和部分索引。在评估这些表达式时发生的错误可能会导致与上述唯一性约束冲突类似的表现。

常规索引构建允许在同一表上同时发生其他常规索引构建,但一次只能在一个表上发生一个并发索引构建。在任何一种情况下,都不允许在构建索引时对表进行架构修改。另一个区别是,常规的 CREATE INDEX 命令可以在事务块内执行,但 CREATE INDEX CONCURRENTLY 不能。

目前不支持对分区表进行并发索引构建。但是,您可以单独并发地在每个分区上构建索引,然后最终非并发地创建分区索引,以减少分区表的写入将被锁定的时间。在这种情况下,构建分区索引只是一个元数据操作。

注释

有关何时可以使用索引、何时不使用索引以及在哪些特定情况下它们可能很有用的信息,请参阅第 11 章

目前,只有 B 树、GiST、GIN 和 BRIN 索引方法支持多键列索引。是否可以有多键列与是否可以在索引中添加 INCLUDE 列无关。索引最多可以有 32 列,包括 INCLUDE 列。(此限制可以在构建 PostgreSQL 时修改。)目前只有 B 树支持唯一索引。

可以为索引的每一列指定一个带有可选参数的运算符类。运算符类标识索引在该列中使用的运算符。例如,一个四字节整数的 B 树索引将使用 int4_ops 类;此运算符类包括四字节整数的比较函数。实际上,通常使用列数据类型的默认运算符类就足够了。设置运算符类的主要目的是,对于某些数据类型,可能存在多种有意义的排序方式。例如,我们可能希望按绝对值或实部对复数数据类型进行排序。我们可以通过为数据类型定义两个运算符类,然后在创建索引时选择适当的类来实现这一点。有关运算符类的更多信息,请参见 第 11.10 节第 36.16 节

当在分区表上调用 CREATE INDEX 时,默认行为是递归到所有分区,以确保它们都具有匹配的索引。首先检查每个分区以确定是否已存在等效索引,如果存在,则该索引将作为分区索引附加到正在创建的索引,该索引将成为其父索引。如果不存在匹配的索引,则将创建一个新索引并自动附加;每个分区中新索引的名称将按照命令中未指定索引名称的方式确定。如果指定了 ONLY 选项,则不会进行递归,并且该索引被标记为无效。(ALTER INDEX ... ATTACH PARTITION 将索引标记为有效,一旦所有分区都获得匹配的索引。)但是请注意,将来使用 CREATE TABLE ... PARTITION OF 创建的任何分区都将自动具有匹配的索引,而无论是否指定 ONLY

对于支持有序扫描的索引方法(目前只有 B 树),可以指定可选的 ASCDESCNULLS FIRST 和/或 NULLS LAST 子句来修改索引的排序顺序。由于有序索引可以向前或向后扫描,因此创建单列 DESC 索引通常没有用处 — 这种排序顺序已经可以通过常规索引获得。这些选项的价值在于,可以创建多列索引,以匹配混合排序查询(例如 SELECT ... ORDER BY x ASC, y DESC)所请求的排序顺序。NULLS 选项在需要支持 空值排序低 行为(而不是默认的 空值排序高)的查询中非常有用,这些查询依赖索引来避免排序步骤。

系统会定期收集表的所有列的统计信息。新创建的非表达式索引可以立即使用这些统计信息来确定索引的有用性。对于新的表达式索引,需要运行 ANALYZE 或等待 自动清理守护进程分析该表以生成这些索引的统计信息。

在运行 CREATE INDEX 时,search_path 临时更改为 pg_catalog, pg_temp

对于大多数索引方法,创建索引的速度取决于 maintenance_work_mem 的设置。较大的值将减少创建索引所需的时间,只要您不使其大于实际可用的内存量,否则会导致机器进入交换。

PostgreSQL 可以在利用多个 CPU 的同时构建索引,以便更快地处理表行。此功能称为并行索引构建。对于支持并行构建索引的索引方法(目前只有 B 树),maintenance_work_mem 指定每个索引构建操作作为一个整体可以使用的最大内存量,而不管启动了多少个工作进程。通常,成本模型会自动确定应请求多少个工作进程(如果有)。

在等效的串行索引构建几乎看不到或根本看不到好处的情况下,并行索引构建可能会从增加 maintenance_work_mem 中受益。请注意,maintenance_work_mem 可能会影响请求的工作进程的数量,因为并行工作进程必须至少拥有总 maintenance_work_mem 预算的 32MB 份额。领导进程也必须剩余 32MB 的份额。增加 max_parallel_maintenance_workers 可能会允许使用更多的工作进程,这将减少创建索引所需的时间,只要索引构建尚未受 I/O 限制。当然,还应有足够的 CPU 容量,否则这些容量将处于空闲状态。

通过 ALTER TABLEparallel_workers 设置一个值,可以直接控制 CREATE INDEX 对表请求的并行工作进程的数量。这完全绕过了成本模型,并阻止 maintenance_work_mem 影响请求的并行工作进程的数量。通过 ALTER TABLEparallel_workers 设置为 0 将在所有情况下禁用表上的并行索引构建。

提示

您可能需要在设置 parallel_workers 后重置它,作为调整索引构建的一部分。这可以避免对查询计划的意外更改,因为 parallel_workers 会影响所有并行表扫描。

虽然带有 CONCURRENTLY 选项的 CREATE INDEX 支持并行构建而没有特殊限制,但实际上只有第一个表扫描是并行执行的。

使用 DROP INDEX 删除索引。

像任何长时间运行的事务一样,表上的 CREATE INDEX 可能会影响并发的 VACUUM 在任何其他表上可以删除哪些元组。

早期版本的 PostgreSQL 也有 R 树索引方法。此方法已被删除,因为它与 GiST 方法相比没有明显的优势。如果指定了 USING rtreeCREATE INDEX 会将其解释为 USING gist,以简化旧数据库到 GiST 的转换。

每个运行 CREATE INDEX 的后端都将在 pg_stat_progress_create_index 视图中报告其进度。有关详细信息,请参见 第 27.4.4 节

示例

要在表 films 中的列 title 上创建唯一的 B 树索引

CREATE UNIQUE INDEX title_idx ON films (title);

要在表 films 中创建包含列 directorrating 的列 title 的唯一 B 树索引

CREATE UNIQUE INDEX title_idx ON films (title) INCLUDE (director, rating);

要创建禁用重复数据删除的 B 树索引

CREATE INDEX title_idx ON films (title) WITH (deduplicate_items = off);

要在表达式 lower(title) 上创建索引,允许进行高效的不区分大小写的搜索

CREATE INDEX ON films ((lower(title)));

(在此示例中,我们选择省略索引名称,因此系统将选择一个名称,通常是 films_lower_idx。)

要创建具有非默认排序规则的索引

CREATE INDEX title_idx_german ON films (title COLLATE "de_DE");

要创建具有非默认空值排序顺序的索引

CREATE INDEX title_idx_nulls_low ON films (title NULLS FIRST);

要创建具有非默认填充因子的索引

CREATE UNIQUE INDEX title_idx ON films (title) WITH (fillfactor = 70);

要创建GIN禁用快速更新的索引

CREATE INDEX gin_idx ON documents_table USING GIN (locations) WITH (fastupdate = off);

要在表 films 的列 code 上创建索引,并将该索引驻留在表空间 indexspace

CREATE INDEX code_idx ON films (code) TABLESPACE indexspace;

要在点属性上创建 GiST 索引,以便我们可以有效地对转换函数的结果使用框运算符

CREATE INDEX pointloc
    ON points USING gist (box(location,location));
SELECT * FROM points
    WHERE box(location,location) && '(0,0),(1,1)'::box;

要创建索引而不锁定对表的写入

CREATE INDEX CONCURRENTLY sales_quantity_index ON sales_table (quantity);

兼容性

CREATE INDEXPostgreSQL 语言扩展。SQL 标准中没有关于索引的规定。

提交更正

如果您发现文档中有任何不正确、与特定功能的使用体验不符或需要进一步澄清的地方,请使用 此表单 报告文档问题。