PostgreSQL非阻塞性创建索引CREATE INDEX CONCURRENTLY

在PostgreSQL中,CREATE INDEX CONCURRENTLY选项允许在创建索引时避免阻塞DML操作,适合生产环境。此过程涉及两次表扫描并在事务中构建索引,可能增加额外的CPU和I/O开销。如果构建过程中出现问题,可能会创建一个无效的索引,需要删除后重新尝试。并发构建唯一索引时,可能在索引可用前就报告违反唯一性约束。并发重建索引从PostgreSQL 12版本开始支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

正常的 create index 是会阻塞 dml 操作的,在生产环境需要添加 concurrently 参数。

CREATE INDEX CONCURRENTLY idx_index_name ON TABLE_NAME ( COLUMN_NAME );

CONCURRENTLY参数说明

CONCURRENTLY
当使用了这个选项时,PostgreSQL在构建索引时 不会取得任何会阻止该表上并发插入、更新或者删除的锁。而标准的索引 构建将会把表锁住以阻止对表的写(但不阻塞读),这种锁定会持续到索 引创建完毕。在使用这个选项时有多个需要注意的地方 — 请见 并发构建索引(如下文)。

并发构建索引

创建索引可能会干扰数据库的常规操作。通常 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重建该索引。不过,由于 REINDEX不支持并发构建,这种选择不那么有吸引力)。

并发构建一个唯一索引时需要注意的另一点是,当第二次表扫描开始时,唯一约束 已经被强制在其他事务上。这意味着在该索引变得可用之前,其他查询中可能就会 报告该约束被违背,或者甚至在索引构建最终失败的情况中也是这样。还有,如果在 第二次扫描时发生失败,“无效的”索引也会继续强制它的唯一性约束。

表达式索引和部分索引的并发构建也被支持。在这些表达式计算过程中发生的 错误可能导致和上述唯一约束违背类似的行为。

常规索引构建允许在同一个表上并行构建其他常规索引,但是在一个表上同时 只能有一个并发索引构建发生。在两种情况下,同时都不允许在表上有其他类 型的模式修改。另一个不同是,一个常规CREATE INDEX 命令可以在一个事务块中执行,但是 CREATE INDEX CONCURRENTLY不行。

版本支持

并发创建索引是从比较早的版本就已经支持了的(9.3之前吧,具体版本未知)。

而,重建索引,是从pg12开始支持并发重建的。

详见:http://www.postgres.cn/docs/12/sql-reindex.html#SQL-REINDEX-CONCURRENTLY


参考:

<think>嗯,用户想了解如何在 PostgreSQL创建索引。首先,我需要回忆一下相关的知识。记得创建索引的基本语法是使用CREATE INDEX命令,对吧?不过可能需要详细说明不同索引类型,比如B-tree、Hash、GiST、SP-GiST、GIN、BRIN这些,因为PostgreSQL支持多种索引类型。 用户可能对基础语法不太清楚,所以需要先介绍最简单的单列索引,比如CREATE INDEX index_name ON table_name (column_name);。然后,组合索引的话,就是多个列的组合,语法应该是CREATE INDEX后面跟上多个列名。还有唯一索引,需要用UNIQUE关键字,这样可以确保列的值唯一。 另外,用户可能不知道索引类型的选择对能的影响。比如B-tree适合范围查询,而GIN适合全文搜索或者数组类型的数据。这时候需要给出不同索引类型的应用场景,帮助用户理解何时使用哪种索引。 还需要注意索引的命名规范,比如使用有意义的名称,方便后续维护。删除索引的语法也要提到,因为用户创建错误时可能需要删除。DROP INDEX index_name; 这样用户就知道如何操作了。 另外,用户可能关心并发创建索引的问题,因为在生产环境中,创建索引可能会锁表,影响能。这时候需要介绍CONCURRENTLY选项,允许在创建索引时不阻塞写操作,但可能会更耗时。 还要考虑示例代码,比如如何在实际表中创建索引,可能用户需要看到具体的例子才能理解。比如引用中的例子,创建了一个表tab_test_1,然后创建索引idx_1,这个例子可以说明创建过程。 另外,用户可能想知道索引的维护,比如重建索引,REINDEX命令,但用户的问题主要是创建,所以暂时不需要深入,但可以提一下相关引用中的信息,比如引用3提到REINDEX,可以作为扩展知识。 还要注意用户可能存在的误区,比如索引并不是越多越好,过多的索引会影响写入能,需要合理使用。这可能是在相关问题的部分提到,比如优化方法中的索引选择。 最后,根据用户提供的引用,需要正确引用相关文献。比如引用4详细说明了创建索引的语法,包括组合索引和唯一索引,所以回答时要对应这些内容。引用5给出了一个实际的创建示例,可以在示例部分引用。 总结一下,回答的结构应该是先介绍基本语法,然后不同索引类型,接着是高级选项如并发创建,再给出示例,最后注意事项和优化建议。确保每一步都清晰,并且引用正确的资料,比如引用2提到创建索引能优化的基本步骤,可以强调这一点。</think>### PostgreSQL 创建索引方法及语法详解 #### 一、基础语法 在 PostgreSQL 中,创建索引的核心语法为: $$CREATE\ [UNIQUE]\ INDEX\ [CONCURRENTLY]\ index\_name\ ON\ table\_name\ [USING\ method]\ (column\_name\ [ASC|DESC], ...);$$ 其中: - `UNIQUE`:表示唯一索引,确保列值唯一[^4] - `CONCURRENTLY`:非阻塞方式创建索引(避免表锁)[^5] - `USING method`:指定索引类型,默认为 B-tree #### 二、常用索引类型及示例 1. **单列索引** ```sql CREATE INDEX idx_employee_name ON employees (last_name); ``` 适用于对单个字段的快速查询,如`WHERE last_name = 'Smith'` 2. **组合索引** ```sql CREATE INDEX idx_emp_dept_salary ON employees (department_id, salary DESC); ``` 优化多条件查询,如`WHERE department_id=5 AND salary>10000` 3. **唯一索引** ```sql CREATE UNIQUE INDEX idx_unique_email ON users (email); ``` 强制保证字段唯一,功能类似`UNIQUE`约束但可包含表达式 4. **函数索引** ```sql CREATE INDEX idx_lower_title ON books (LOWER(title)); ``` 支持对表达式计算结果建立索引 #### 三、高级索引类型 | 索引类型 | 适用场景 | 示例 | |----------|---------------------------|--------------------------| | GiST | 地理数据、全文搜索 | `USING GIST(geom_column)` | | GIN | 数组、JSONB、全文搜索 | `USING GIN(jsonb_column)` | | BRIN | 大型有序数据集 | `USING BRIN(create_time)` | #### 四、并发创建索引 为避免锁表影响业务,建议生产环境使用: ```sql CREATE INDEX CONCURRENTLY idx_orders_date ON orders (order_date); ``` 注意:此方式耗时更长且需要额外磁盘空间[^5] #### 五、索引管理 1. 查看索引 ```sql \d table_name -- 在psql中查看 ``` 2. 删除索引 ```sql DROP INDEX IF EXISTS idx_old_index; ``` #### 六、最佳实践 1. 优先为`WHERE`子句和`JOIN`条件中的列建索引[^2] 2. 避免对频繁更新的表创建过多索引 3. 定期使用`REINDEX`重建碎片化索引[^3] 4. 对大表使用`pg_repack`进行在线重建
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值