mysql 8.0原子ddl更安全的根本原因是废除.frm文件和非事务系统表,将全部元数据存入innodb管理的mysql.*系统表,使其具备事务、redo log和崩溃恢复能力。

MySQL 8.0 的原子 DDL 更安全,根本原因不是“加了新功能”,而是彻底废掉了.frm文件和非事务性系统表,把所有元数据都塞进 InnoDB 引擎管理的 mysql.* 系统表里——元数据从此有了事务、redo log、崩溃恢复能力。
为什么.frm文件是旧版DDL不安全的根源
在 MySQL 5.7 及以前,ALTER TABLE 实际要协调三件事:改.frm文件(文件系统操作)、更新 InnoDB 内部字典(InnoDB 事务)、写 binlog(Server 层日志)。这三者完全独立,没有统一事务兜底。一旦中途崩溃:
- 服务器重启后可能读到旧的.frm但 InnoDB 已按新结构加载,报错
Table definition has changed, please retry transaction - 或者.frm删了,InnoDB 字典还留着,导致
DROP TABLE失败却提示“表不存在” -
DROP TABLE t1, t2这种批量操作,极容易出现只删掉一个表就中断,留下半残状态
Data Dictionary 如何让元数据真正受事务保护
MySQL 8.0 把 mysql.tables、mysql.columns、mysql.indexes 全部变成 InnoDB 表,存进 mysql.ibd。这意味着:
- 每次 DDL 都是一组对这些系统表的 INSERT/UPDATE/DELETE,天然走 InnoDB 事务流程
- 崩溃时,InnoDB 崩溃恢复机制自动回滚未提交的 DDL 事务,不会留下“字典已改、文件没动”或“文件已删、字典还在”的撕裂状态
-
information_schema查询结果与实际表结构永远一致,不再依赖缓存或外部文件同步
DDL_LOG 表补上了物理操作的最后缺口
光靠事务性字典还不够:创建文件、重命名.ibd、清理 buffer pool 缓存这些操作本身不记 redo。MySQL 8.0 用 mysql.innodb_ddl_log 表来记录它们:
- DDL 执行前,先往
innodb_ddl_log插入一条“如果失败,该执行 REMOVECACHE 或 DELETESPACE”的指令 - DDL 提交后,进入
post_ddl阶段,才真正执行文件系统操作,并顺手删掉对应 log 记录 - 若 crash 发生在 post_ddl 前,重启后会重放
innodb_ddl_log中的指令,确保物理层和字典层最终一致
你真正该关心的“安全边界”在哪
原子 DDL 保证的是单条语句内部的强一致性,但它不解决并发场景下的可见性问题:
- 长事务未结束时执行
ALTER TABLE,DDL 会卡在 MDL 锁等待,而其他会话查information_schema.COLUMNS仍看到旧结构——这不是不安全,是隔离性正常表现 -
ALTER TABLE ... ALGORITHM=COPY不走原子 DDL 流程,它绕过数据字典事务,直接重建表,风险回归 5.7 模式 - 跨库
RENAME TABLE db1.t TO db2.t不支持原子性,因为涉及两个库的数据字典事务,MySQL 不支持跨库事务
所以别只盯着“原子”二字——重点看你的 DDL 是否落在官方文档标记为 “Atomic DDL supported: Yes” 的列表里,再确认没触发 COPY 算法或跨库操作。这才是线上真正可控的安全线。











