MySQL 8.0 原子 DDL 保证 DDL 操作“全有或全无”,通过将元数据统一存入 InnoDB 系统表并纳入 ACID 事务,崩溃后由 InnoDB 自动回滚,配合 mysql.innodb_ddl_log 表确保文件操作原子性。

MySQL 8.0 的原子 DDL 不是让 ALTER 更快,而是让它“改不成就等于没改”——只要崩溃、磁盘满、KILL -9 发生在任意中间环节,重启后你看到的永远是完整的旧结构或完整的新结构,绝不会出现 Table definition has changed, please retry transaction 这种进退两难的状态。
DDL 崩溃后为什么 MySQL 5.7 会留“残血表”
老版本把元数据拆成三块裸奔:.frm 文件改了、InnoDB 字典更新了、binlog 最后写。这三步互不认账:
- 断电卡在第二步之后?InnoDB 认为列已存在,但 .frm 还是旧的 → 客户端读表直接报错
-
DROP TABLE t1, t2中t2不存在?t1被删光,t2报错退出,没回滚机制兜底 - 从库复制时发现 binlog 缺这条 DDL?可能跳过或卡死,主从元数据永久错位
MySQL 8.0 原子 DDL 实际靠什么保证“全有或全无”
核心不是加了新功能,而是把所有元数据(表、列、索引、用户)全搬进 mysql.tables、mysql.columns 这些 InnoDB 系统表里,和业务数据一样走 ACID:
- 一次
ALTER TABLE就是一个标准 InnoDB 事务:字典表变更 + 引擎内存对象更新(如dict_table_t)+ binlog 写入,全部打包提交 - 崩溃重启后,InnoDB 崩溃恢复机制自动回滚整个事务——就像它从来没发生过
-
mysql.innodb_ddl_log表(藏在mysql.ibd里)记录前滚/回滚指令,确保文件操作(如重命名 .ibd)只在 post-ddl 阶段执行,避免中间态残留
哪些 ALTER TABLE 真正受原子性保护
别被“MySQL 8.0 支持原子 DDL”误导——它只对明确标注 Atomic DDL supported: Yes 的操作生效:
- ✅ 安全:
ADD COLUMN(末尾添加)、DROP COLUMN(InnoDB 表)、ADD INDEX/DROP INDEX(非全文)、RENAME TABLE(同库内)、ALTER TABLE ENGINE=InnoDB - ❌ 不安全:
MODIFY COLUMN、CHANGE COLUMN、OPTIMIZE TABLE、跨库RENAME TABLE——它们可能部分回退,但不进原子事务流程 - ⚠️ 注意:
ALGORITHM=INSTANT只是快,不是原子;START TRANSACTION包裹多条 DDL 有用,但一旦混入不支持原子的操作(如MODIFY COLUMN),整个事务立即失败,已执行的原子操作也不会回滚
线上执行前必须确认的三个硬条件
原子性默认开启,但有两个隐藏前提必须满足,否则 DDL 直接失败:
-
innodb_force_recovery必须为0(即正常模式),设成 1–6 时原子事务无法启动 -
mysql.innodb_ddl_log表必须可写——若磁盘满、权限异常或mysql.ibd只读,会报ER_DDL_LOG_ERROR - 目标表不能被长事务持有 MDL 锁:查
information_schema.INNODB_TRX,避免卡在Waiting for table metadata lock
真正危险的不是 DDL 失败,而是你以为它失败了其实改了一半,或者你以为它成功了其实 binlog 没写、从库已经脱节。原子 DDL 解决的是最底层的元数据一致性,但它不管并发锁、不兜底客户端缓存、也不替你判断 MODIFY COLUMN 是否真该用。用之前,先看官方文档里那句小字:Atomic DDL supported: Yes。


















