选择 打开 改范围 完整检索页

pgsql.cc 提供对 postgresql.org 官网内容的中文翻译,由 Pigsty 团队维护。

受支持版本: 当前版本 (18) / 17 / 16 / 15 / 14
测试与开发版本: 19 / devel
不受支持的版本: 13 / 12 / 11 / 10 / 9.6 / 9.5 / 9.4 / 9.3 / 9.2 / 9.1 / 9.0
历史版本PostgreSQL 9.1 已于 2016 年 10 月结束社区维护,本页译文保留供仍在使用旧版本的读者参考。新系统请看当前版本

CREATE INDEX

CREATE INDEX — define a new index

大纲

CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] [ name ] ON table [ USING method ]
    ( { column | ( expression ) } [ COLLATE collation ] [ opclass ] [ ASC | DESC ] [ NULLS { FIRST | LAST } ] [, ...] )
    [ WITH ( storage_parameter = value [, ... ] ) ]
    [ TABLESPACE tablespace ]
    [ WHERE predicate ]

描述

CREATE INDEX 在指定表的指定列上构建一个索引。索引主要用于提升数据库性能(但使用不当也可能导致性能下降)。

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

索引字段可以是根据表行中一个或多个列值计算得到的表达式。 该特性可用于根据基础数据的某种变换来快速访问数据。例如, 在upper(col)上计算的索引可让子句 WHERE upper(col) = 'JIM'使用索引。

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

WHERE子句存在时,会创建一个 部分索引。部分索引只包含表中一部分行的索引项, 通常这一部分比表的其余部分更适合建立索引。例如,如果一个表同时包含 已开票和未开票订单,而未开票订单只占整个表的一小部分,但这一部分又经常 被访问,就可以只对这部分创建索引来提升性能。另一种可能 的应用是将WHEREUNIQUE结合使用, 以便在表的一个子集上强制唯一性。更多讨论请见 第 11.8 节

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

所有在索引定义中使用的函数和操作符都必须是不可变的, 也就是说,它们的结果只能依赖其参数,而不能受任何外部因素影响 (例如另一个表的内容或当前时间)。这种限制确保索引的行为定义明确。 要在索引表达式或WHERE子句中使用用户定义的函数, 记得在创建该函数时将其标记为不可变。

参数

UNIQUE

使系统在创建索引时(如果数据已经存在)以及每次添加数据时, 检查表中的重复值。任何会导致重复项的插入或更新操作都会报错。

CONCURRENTLY

使用此选项时,PostgreSQL将在构建索引时不获取任何会阻止对表进行并发插入、更新或删除的锁;而标准索引构建会阻塞对表的写入(但不会阻塞读取),直到构建完成。使用此选项时有几个注意事项需要了解—请参见并发构建索引

name

要创建的索引名称。此处不能包含模式名称;索引始终创建在其父表所在的同一模式中。如果省略名称,PostgreSQL会根据父表名称和被索引的列名选择合适的名称。

table

要建立索引的表名(可以是模式限定名)。

method

要使用的索引方法的名称。选择包括 btreehashgistgin。默认方法是 btree

column

一个表列的名称。

expression

一个基于表中一个或多个列的表达式。通常必须像语法中所示那样写在 外围圆括号中。不过,如果该表达式是函数调用形式,则可以省略圆括号。

collation

将用于该索引的排序规则名称。默认情况下,索引使用被索引列声明的 排序规则,或者被索引表达式的结果排序规则。对于涉及使用非默认排序 规则表达式的查询,使用非默认排序规则的索引可能会很有用。

opclass

一个操作符类的名称。详见下文。

ASC

指定升序排序(默认)。

DESC

指定降序排序。

NULLS FIRST

指定把空值排序在非空值前面。在指定DESC时, 这是默认行为。

NULLS LAST

指定把空值排序在非空值后面。在没有指定DESC时, 这是默认行为。

storage_parameter

索引方法专用存储参数的名称。有关详细信息,请参见索引存储参数

tablespace

在其中创建索引的表空间。如果未指定,将查阅 default_tablespace;对于临时表上的索引,则查阅 temp_tablespaces

predicate

部分索引的约束表达式。

索引存储参数

可选的 WITH 子句为索引指定存储参数。每一种索引方法都有其各自允许的存储参数集合。B-树、哈希和 GiST 索引方法都接受一个参数:

FILLFACTOR

索引的填充因子是一个百分比,用于确定索引方法将尝试把索引页填充到多满。对于 B-树,在初始构建索引期间,以及向右扩展索引(添加新的最大键值)时,叶页都会填充到该百分比。如果之后页面变得完全填满,就会进行拆分,导致索引效率逐渐下降。B-树 使用默认填充因子 90,但可以选择 10 到 100 之间的任意整数值。如果表是静态的,填充因子 100 最适合将索引的物理大小降至最低;但对于频繁更新的表,较小的填充因子更适合减少页面拆分的需要。其他索引方法以不同但大致类似的方式使用填充因子;默认填充因子因方法而异。

GIN 索引接受不同的参数:

FASTUPDATE

此设置控制第 54.3.1 节中描述的快速更新技术的使用。这是一个布尔参数:ON启用快速更新,OFF禁用快速更新。(如第 18.1 节中所述,允许使用ONOFF的其他拼写形式。)默认值为ON

注意

通过ALTER INDEX关闭fastupdate 会阻止后续插入进入待处理索引项列表,但这本身不会刷新现有条目。 之后可能需要对该表执行VACUUM,以确保待处理列表被清空。

并发构建索引

创建索引可能会干扰数据库的正常运行。通常 PostgreSQL会锁住要建立索引的表,阻止其写入, 并通过一次扫描完成整个索引构建。其他事务仍可读取该表,但如果它们试图 在表中插入、更新或删除行,就会阻塞直到索引构建完成。如果系统是在线生 产数据库,这可能产生严重影响。对非常大的表建立索引可能需要很多小时, 即便是较小的表,索引构建也可能在一段对生产系统而言不可接受的时间内阻 止写入者操作。

PostgreSQL支持在不阻止写入的情况下构建索引。 这种方法通过在CREATE INDEX中指定 CONCURRENTLY选项来启用。使用该选项时, PostgreSQL必须对该表执行两次扫描,此外还 必须等待所有现有、可能修改或使用该索引的事务结束。因此,这种方法比标 准索引构建需要更多总工作量,完成时间也明显更长。不过,由于它允许在构 建索引期间继续进行正常操作,所以这种方法适合在生产环境中新增索引。当 然,创建索引带来的额外 CPU 和 I/O 负载也可能拖慢其他操作。

在并发索引构建中,索引实际上会在一个事务中录入系统目录,然后在另外两个事务中执行两次表扫描。每次表扫描之前,索引构建都必须等待已修改该表的现有事务结束。第二次扫描之后,索引构建必须等待所有持有早于第二次扫描的快照(参见第 13 章)的事务结束,其中包括其他表上并发索引构建任一阶段使用的事务。最后,索引才可以标记为可用,CREATE INDEX命令随之结束。不过即便如此,索引也可能无法立即用于查询:在最坏情况下,只要还存在早于索引构建开始的事务,就不能使用它。

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

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

在这种情况下,建议的恢复方法是删除索引,然后重新尝试执行CREATE INDEX CONCURRENTLY。(另一种可能性是重建索引,使用REINDEX。但是,由于REINDEX不支持并发构建,此选项不太有吸引力。)

并发构建唯一索引时的另一项注意事项是,在第二次表扫描开始时,唯一性约 束就已经开始对其他事务生效了。这意味着在该索引可供使用之前,其他查询 就可能报告约束违规,甚至在索引构建最终失败的情况下也是如此。另外,如 果第二次扫描确实失败了,那个无效索引之后仍会继续强制 执行其唯一性约束。

也支持并发构建表达式索引和部分索引。计算这些表达式时发生的错误, 可能导致与上文所述唯一性约束违规类似的行为。

普通索引构建允许同一表上的其他普通索引构建并行进行,但一张表上一次只能进行一个并发索引构建。在这两种情况下,期间都不允许对该表进行其他类型的模式修改。另一个区别是,普通CREATE INDEX命令可以在事务块中执行,而CREATE INDEX CONCURRENTLY不能。

注解

关于索引何时能被使用、何时不被使用以及什么情况下它们有用的信息请 见第 11 章

小心

哈希索引操作目前不会写入 WAL 日志,因此如果数据库崩溃时还有未写入 的更改,哈希索引可能需要用REINDEX重建。此外, 在初始基础备份之后,对哈希索引的更改不会通过流复制或基于文件的 复制进行复制,因此之后使用这些索引的查询会得到错误的答案。哈希 索引在时间点恢复期间也不能被正确恢复。由于这些原因,目前不鼓励 使用哈希索引。

目前,只有 B-树、GiST 和 GIN 索引方法支持多列索引。默认最多可指定 32 个字段。(构建PostgreSQL时可以更改此限制。)目前只有 B-树 支持唯一索引。

索引的每一列都可以指定一个操作符类。操作符类标识索引用于该列的操作符。例如,四字节整数上的 B-树 索引会使用int4_ops类;此操作符类包含四字节整数的比较函数。实际上,列数据类型的默认操作符类通常已足够。操作符类存在的主要原因是,某些数据类型可能有多个有意义的排序方式。例如,我们可能希望按绝对值或实部对复数数据类型排序。我们可以为该数据类型定义两个操作符类,并在创建索引时选择合适的类。有关操作符类的更多信息,请参见第 11.9 节第 35.14 节

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

对于大多数索引方法,索引的创建速度取决于 maintenance_work_mem的设置。较大的值将会减少 索引创建所需的时间,当然不要把它设置得超过实际可用的内存量(那会迫使 机器进行交换)。

使用DROP INDEX删除索引。

早期版本的PostgreSQL还提供过一种 R-tree 索引方法。该方法已经被移除,因为它相对于 GiST 方法并无明显优势。如果 指定了USING rtreeCREATE INDEX 会将其解释为USING gist,以简化旧数据库向 GiST 的转换。

示例

创建 B-树索引,列为title,所在表为films

CREATE UNIQUE INDEX title_idx ON films (title);

要在表达式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 索引,以便能够在转换函数的结果上高效地使用 box 操作符:

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 标准中没有关于 索引的规定。

提交更正

译文有误、术语不当或页面显示问题,请到译文仓库 pgsty/pgdoc 报告译文问题。 英文原文本身的问题,请在当前版本的对应页面向上游反馈;上游不再修订已结束维护的版本。