MySQL 8.0移除.frm文件是为了根治元数据不一致、DDL崩溃残留等运维痛点,通过将表结构等元数据统一存入事务型InnoDB系统表(如mysql.tables、mysql.columns),实现原子DDL和崩溃安全,而非单纯追求技术先进性。

MySQL 8.0 完全采用 InnoDB 数据字典,不是为了“更现代”,而是为了解决 MySQL 5.7 及之前版本中长期存在的元数据不一致、DDL 崩溃残留、升级失败等实际运维痛点。核心判断是:这是架构层面的纠错,而非功能增强。
为什么.frm文件会导致“Table doesn't exist”这类错误
在 MySQL 5.7 中,Server 层写 .frm 文件,InnoDB 引擎又在 ibdata1 里存一份表定义,两者无事务保障。一旦 ALTER TABLE 过程中崩溃,就可能出现:
-
.frm已更新但 InnoDB 字典未提交 → 启动时按.frm加载表,却查不到对应dict_table_t对象,报错Table 'db.t1' doesn't exist - InnoDB 已建好新索引结构,但
.frm还是旧版 → 查询INFORMATION_SCHEMA.COLUMNS显示字段缺失或类型错乱 - 备份恢复时只拷了
.ibd却漏掉.frm,或反之 → 表不可用且无法自动修复
mysql.tables 和 mysql.columns 是怎么替代.frm的
MySQL 8.0 把原来分散在文件和非事务表里的元数据,全部收编进 mysql 库下的 InnoDB 系统表,例如:
-
mysql.tables存表名、引擎、字符集、行格式等基础属性 -
mysql.columns存字段名、类型、长度、是否为空、默认值(含表达式) -
mysql.indexes和mysql.index_column_usage管理索引定义与列顺序 - 所有这些表都走 InnoDB 的 redo/undo 日志,
CREATE TABLE或DROP INDEX失败时自动回滚,不留半成品
注意:ibd2sdi 命令可从 .ibd 文件中提取嵌入的 SDI(Serialized Dictionary Information),但它只是 JSON 备份,不含外键、触发器、存储过程等完整 DDL —— 真正权威来源永远是 mysql 库下的系统表。
原子 DDL 背后依赖的是数据字典的事务性
所谓“原子 DDL”,本质是把 DDL 操作拆解为对数据字典表的多条 DML + 物理文件操作,并包裹在同一个 InnoDB 事务中。比如:
-
CREATE TABLE t1 (id INT) ENGINE=InnoDB会同时写入mysql.tables、mysql.columns、mysql.indexes,并创建t1.ibd - 任意一步失败(如磁盘满、权限不足),整个事务 rollback,
mysql表无残留,t1.ibd也被自动清理 - 这意味着你不再需要手动检查
SHOW CREATE TABLE和ls -l *.frm是否匹配 —— 根本没有.frm了
这个机制依赖 sql/dd/ 目录下的数据字典 API(如 dd::Table::store())与 InnoDB 层的深度集成,不是简单加个事务 BEGIN 就能实现的。
迁移和兼容性要注意什么
升级到 MySQL 8.0 时,mysql_upgrade 会执行 mysqld --upgrade=FORCE,将旧版 .frm 和 mysql 表中的元数据一次性导入新字典表。这个过程不可逆,且:
- 升级后无法降级回 5.7 —— 新字典表结构不被旧版本识别
- 如果原库含 MyISAM 表,其元数据也会被转存进
mysql.tables,但 MyISAM 引擎本身不参与事务,DROP TABLE仍可能残留.MYD/.MYI文件 -
INFORMATION_SCHEMA视图底层已全部重写为查询mysql系统表,所以SELECT * FROM INFORMATION_SCHEMA.COLUMNS实际走的是 InnoDB 缓冲池,性能比 5.7 更稳定
真正容易被忽略的是:SDI 虽然嵌在每个 .ibd 里用于灾难恢复,但它不参与日常 DDL 流程,也不保证实时同步;线上排查问题必须以 mysql 库下真实系统表为准,而不是靠 ibd2sdi 解析出来的快照。


















