mysql 5.7不支持同一表并发alter table,因mdl锁全程持有导致阻塞;连续ddl可能因残留状态(如临时表、.frm文件)或外键依赖报错;安全做法是合并操作、优先inplace、避开高峰并监控mdl等待。

MySQL 5.7 **根本就支持**在同一个表上执行多个 DDL(比如连续 ALTER TABLE),但不支持「并发执行」——即多个连接同时对同一张表发 ALTER TABLE,会阻塞、排队甚至报错。这不是语法限制,而是锁机制和非原子 DDL 的必然结果。
为什么并发 ALTER 同一张表会卡住或失败
5.7 中 ALTER TABLE 操作需要获取表级元数据锁(MDL),且全程持有直到事务提交(即使语句本身不显式开启事务)。这意味着:
- 第一个
ALTER TABLE t ADD COLUMN c1 INT开始后,其他连接对t的任何 DDL(包括DROP INDEX、RENAME TO)都会被挂起,等待 MDL 释放 - 如果第一个操作因大表拷贝、磁盘慢、或被 kill 中断,MDL 可能长时间滞留,导致后续所有 DDL 堆积在
Waiting for table metadata lock - 更隐蔽的是:哪怕你用
ALGORITHM=INPLACE,只要涉及索引重建或列重排,仍需短暂的EXCLUSIVEMDL,足以阻塞其他 DDL
为什么“连续执行多个 DDL”有时也报错
不是语法不允许,而是中间状态残留引发冲突。典型场景:
-
ALTER TABLE t DROP COLUMN a; ALTER TABLE t ADD COLUMN a VARCHAR(10);看似等价于修改类型,但 5.7 会先删再加 → 第二条执行时若发现a已存在(比如第一条没真正完成,.frm 文件残留),直接报ERROR 1060 (42S21): Duplicate column name 'a' - 使用
ALGORITHM=COPY时,若中途 crash,可能留下临时表#sql-xxx,后续 DDL 会因同名冲突失败,而DROP TABLE #sql-xxx在 5.7 中常卡死,无法手动清理 - 触发器或外键依赖该表时,DDL 顺序稍有不慎(如先删列再删外键),会触发
ERROR 1829 (HY000): Cannot drop column 'x': needed in a foreign key constraint
5.7 下安全批量改表的实操原则
没有“同时执行”的捷径,只有降低风险的组合策略:
- 把多个 DDL 合并成一条(如果语义允许):
ALTER TABLE t ADD COLUMN c1 INT, DROP COLUMN c2, MODIFY c3 BIGINT;—— 减少锁持有次数,且全部在一个 MDL 周期内完成 - 确认存储引擎支持
INPLACE:InnoDB 大部分结构变更可ALGORITHM=INPLACE, LOCK=NONE,但 MyISAM 必须COPY,完全不可并发 - 避开业务高峰,并监控
SHOW PROCESSLIST中的Waiting for table metadata lock状态,及时 kill 滞留连接 - 绝不依赖
.frm文件一致性:crash 后若发现表异常,优先用mysqlcheck --repair或从备份恢复,而非手动删.frm
真正容易被忽略的是:5.7 的 DDL 阻塞是“无声”的——它不报错,只是无限等待。你看到的“执行不动”,大概率是 MDL 死锁或前序 DDL 卡在 IO 上,而不是语句写错了。











