首页/数据/SQL 速查/在线创建索引:INPLACE 与 CONCURRENTLY
性能与执行计划72 条

在线创建索引:INPLACE 与 CONCURRENTLY

生产环境加索引要控制阻塞:MySQL 8.0 用 ALGORITHM/LOCK 子句约束在线 DDL;PostgreSQL 用 CREATE INDEX CONCURRENTLY。

SQL 速查数据更新于 2026-10-13

生产环境加索引不阻塞业务

在大表上加索引如果按默认方式执行,会长时间持有较强的锁,业务写入被挡在外面。两种数据库都提供了降低阻塞的手段:MySQL 可以在变更语句里显式声明算法与锁级别,让不支持在线执行的场景直接报错而不是偷偷退化成锁表;PostgreSQL 用专门的并发建索引语句,代价是耗时更长、不能在事务块里执行,中途失败还会留下无效索引需要清理。

基本信息

适用平台MySQL 8.0 / PostgreSQL 12 及以上
MySQL 手段变更语句里显式声明算法与锁级别
PostgreSQL 手段并发建索引语句,专门为不阻塞写入设计
事务限制PostgreSQL 的并发建索引不能在事务块内执行
失败残留PostgreSQL 失败会留下无效索引,需删除后重试

典型使用场景

  • 线上大表加索引:要求写入不被长时间阻塞
  • 索引重建:碎片化严重时重新构建
  • 变更前的可行性验证:确认操作是否支持在线执行
  • 清理失败残留:删除无效索引后重新创建
  • 评估执行窗口:结合复制延迟与磁盘压力安排时间

两库在线加索引

两库在线加索引
-- MySQL:显式声明算法与锁级别
ALTER TABLE orders
  ADD INDEX idx_status (status), ALGORITHM=INPLACE, LOCK=NONE;
-- 若引擎或操作不支持,语句直接报错,而不是退化成锁表执行

-- PostgreSQL:并发建索引,降低锁级别
CREATE INDEX CONCURRENTLY idx_orders_status ON orders (status);
-- 不能在事务块中执行;需额外扫描与等待,耗时更长

-- 失败会留下无效索引,先清理再重试
DROP INDEX CONCURRENTLY idx_orders_status;

-- 确认索引是否有效
-- SELECT indexrelid::regclass, indisvalid FROM pg_index
-- WHERE indrelid = 'orders'::regclass;

-- 执行期间关注复制延迟与磁盘占用

要点对照

要点MySQLPostgreSQL
声明方式变更语句内的算法与锁子句专用的并发建索引语句
不支持时直接报错,不退化不适用
能否放事务里可以不可以,会报错
耗时相对较短更长,需要额外扫描
失败残留自动回滚留下无效索引需手动清理
MySQL 显式声明算法与锁级别的价值在于「宁可报错也不锁表」:不支持在线执行时立刻失败,避免在业务高峰期悄悄执行一次阻塞全表的操作。
PostgreSQL 的并发建索引对写入影响小,但对资源消耗更大,而且需要等待已有事务结束。安排在业务低峰、并观察复制延迟,是常规做法。

易错点

  • 不声明算法与锁级别直接加索引:不支持在线执行时退化成锁表,业务写入被阻塞
  • 把并发建索引语句放进事务块:直接报错终止,变更没有执行
  • 并发建索引失败未清理无效索引就重试:同名冲突让重试一直失败
  • 在业务高峰执行索引变更:即使在线执行也有资源开销与复制延迟风险
  • 忽略磁盘空间:建索引期间索引与原结构并存,空间不足会让变更中途失败

数据来源与参考

  • MySQL 8.0 Reference Manual · Online DDL Operations
  • PostgreSQL Documentation · Building Indexes Concurrently
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌