MySQL 8.0原子DDL指单条DDL自身具备原子性,由隐式事务保障“全成或全不成”,不可嵌入用户显式事务;仅官方标注支持的操作(如ADD/DROP COLUMN、ADD/DROP INDEX等)在InnoDB上具备崩溃级原子保障。

原子DDL不是“事务里能执行DDL”的意思
很多人看到“原子”就默认能写 BEGIN + ALTER TABLE + COMMIT,结果直接报错 ERROR 1785 (HY000): Statement violates GTID consistency 或 ERROR 1305 (42000): SAVEPOINT does not exist。MySQL 8.0 的原子 DDL 指的是单条 DDL 自身具备原子性——它被自动包裹在一个隐式事务中,不接受用户显式控制。你不能也不该把它塞进自己的 START TRANSACTION 块里。
真正安全的做法是:每条 DDL 独立执行,靠 MySQL 内部机制保证“全成或全不成”。混用显式事务反而会触发校验失败,已执行的原子操作也不会回滚(比如先 CREATE TABLE 成功,再 ALTER TABLE 报错,表仍存在)。
哪些 ALTER TABLE 真正受原子性保护
不是所有 ALTER TABLE 都安全。官方只对明确标注 Atomic DDL supported: Yes 的子集提供崩溃级原子保障:
-
ADD COLUMN(末尾添加,且不触发ALGORITHM=COPY) -
DROP COLUMN(InnoDB 表,非全文索引列) -
ADD INDEX/DROP INDEX(不含FULLTEXT) -
RENAME TABLE(同一 schema 内) -
ALTER TABLE ... ENGINE=InnoDB(隐式重建)
而这些操作明确不支持原子性:MODIFY COLUMN、CHANGE COLUMN、OPTIMIZE TABLE、跨库 RENAME TABLE。它们失败时可能已修改部分元数据,无法整体回滚。
崩溃后怎么验证原子性生效了
别光看有没有报错。服务器异常重启后,必须交叉验证两件事:
- 执行
SHOW CREATE TABLE t1—— 结构必须是完整旧版或完整新版,绝不会出现“新增了列但索引丢失”或“字段类型改了一半”这种中间态 - 查
SELECT * FROM information_schema.INNODB_TABLES WHERE NAME = 'your_db/t1',再对比mysql.columns中对应记录是否一致;若不一致,说明原子性没兜住(极罕见,通常意味着系统表损坏)
注意:innodb_ddl_log 表不可见,也不能手动查询,它是崩溃恢复时由 MySQL 启动阶段自动扫描并处理的内部日志。
INSTANT 算法 ≠ 原子性,但能缩短锁窗口
ALGORITHM=INSTANT 是性能优化手段,仅适用于 ADD COLUMN、SET DEFAULT、RENAME COLUMN 等极少数操作。它跳过拷表阶段,MDL 锁持有时间可压到毫秒级,但失败时依然走原子回滚流程。
容易踩的坑:
- 误以为 INSTANT 就等于“绝对不锁表”——其实仍需短暂
MDL_EXCLUSIVE锁来提交字典变更 - 在大表上盲目加
ALGORITHM=INSTANT却不检查是否满足条件(如列不能是主键、不能有全文索引),导致退化为 COPY 模式,锁时反而更长 - 把 INSTANT 当成原子性的替代品——它解决的是阻塞问题,不是崩溃一致性问题
真正关键的判断点永远是:操作是否在官方支持列表里、是否运行在 InnoDB 引擎上、是否避开 MODIFY/CHANGE 这类高危语法。其他都是锦上添花。











