使用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的事务机制会一直持有事务不释放,最终导致操作卡住。
解决步骤
单独拆分演进脚本
把带CONCURRENTLY的索引创建语句单独放在一个演进文件里,不要和其他DDL语句混写,避免事务冲突。修改脚本适配无事务执行
在脚本开头开启自动提交,执行完索引创建后再恢复,示例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;
注意执行特性
CREATE INDEX CONCURRENTLY本身就是低锁但执行较慢的操作,哪怕是小数据集,也需要等待索引构建完成,不要误判为挂起——可以通过数据库的系统视图(比如PostgreSQL的pg_stat_activity)查看索引创建进度。其他数据库适配
如果使用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
相关产品推荐
相关产品推荐

