You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用CREATE INDEX CONCURRENTLY导致Play框架数据库Schema演进挂起

Play 2.6.15 Schema演进使用CREATE INDEX CONCURRENTLY挂起的解决办法

问题背景

要给超大表的某列添加索引,为避免锁表尝试使用CREATE INDEX CONCURRENTLY,但在小数据集测试时发现Play的Schema演进直接挂起;移除CONCURRENTLY后,演进可快速完成。使用的Play版本依赖:

"com.typesafe.play" %% "play" % "2.6.15",
"com.typesafe.play" %% "play-java" % "2.6.15",

核心原因

Play Evolutions(Schema演进组件)默认会将单脚本内的所有DDL语句放在一个事务中执行,但CREATE INDEX CONCURRENTLY(以PostgreSQL为例)不允许在事务块内运行——它会强制要求立即提交事务,而Play的事务机制会一直持有事务不释放,最终导致操作卡住。

解决步骤

  1. 单独拆分演进脚本
    把带CONCURRENTLY的索引创建语句单独放在一个演进文件里,不要和其他DDL语句混写,避免事务冲突。

  2. 修改脚本适配无事务执行
    在脚本开头开启自动提交,执行完索引创建后再恢复,示例PostgreSQL脚本:

-- !Ups
SET autocommit = ON;
CREATE INDEX CONCURRENTLY idx_large_table_target_col ON large_table (target_column);
SET autocommit = OFF;

-- !Downs
DROP INDEX IF EXISTS idx_large_table_target_col;
  1. 注意执行特性
    CREATE INDEX CONCURRENTLY本身就是低锁但执行较慢的操作,哪怕是小数据集,也需要等待索引构建完成,不要误判为挂起——可以通过数据库的系统视图(比如PostgreSQL的pg_stat_activity)查看索引创建进度。

  2. 其他数据库适配
    如果使用MySQL 8.0.29+,可以用无锁建索引语句替代:

-- !Ups
SET autocommit = ON;
ALTER TABLE large_table ADD INDEX idx_large_table_target_col (target_column) ALGORITHM=INPLACE, LOCK=NONE;
SET autocommit = OFF;

-- !Downs
DROP INDEX IF EXISTS idx_large_table_target_col;

内容的提问来源于stack exchange,提问作者GeauxEric

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 15:20:41