MySQL 8.0误删.frm后必须用ibd2sdi提取.ibd中的SDI表结构,因.frm已移除,表定义仅存于.ibd头部;该工具离线解析、不依赖mysqld,是唯一可行入口,且字段顺序、ROW_FORMAT等必须严格匹配才能成功IMPORT TABLESPACE。

MySQL 8.0 误删 .frm 文件后,不能靠复制或重建空表来“蒙混过关”——因为 .frm 已被彻底移除,表结构只存在于 .ibd 内部的 SDI(Serialized Dictionary Information)中。必须用 ibd2sdi 提取并解析它,否则 SHOW CREATE TABLE、DESC 全部失效,表名虽在 information_schema.TABLES 里,但访问即报 ERROR 1146 (42S02): Table doesn't exist。
为什么 ibd2sdi 是唯一可行入口
MySQL 8.0+ 废除了 .frm,把表定义冗余写进每个 .ibd 文件头部(SDI 区域),和数据字典表(mysql.ibd)保持同步。一旦系统表空间损坏或实例无法启动,SDI 仍是唯一可读的结构源——前提是 .ibd 文件本身未加密、未压缩、且 ROW_FORMAT 是 Dynamic 或 Compact。
-
ibd2sdi是 MySQL 8.0.13+ 自带工具,无需额外安装,路径通常在bin/目录下 - 它不依赖运行中的 mysqld 实例,纯文件解析,适合离线恢复场景
- 若
.ibd是Compressed或Encrypted格式,ibd2sdi会直接报错:Error: Unsupported page type,必须先解密/解压再操作
执行 ibd2sdi 的关键参数与常见错误
命令格式看似简单,但参数选错会导致输出为空或 JSON 解析失败:
- 必须加
--dump-file=xxx.json,否则默认输出到 stdout,容易被终端截断或乱码 - 不要用
--type=table(已废弃),新版只认--dump-file和输入.ibd路径 - 常见错误:
ERROR: Failed to read SDI from file—— 多半是.ibd文件权限不对(需 mysql 用户可读),或文件已被部分覆盖/损坏 - 成功执行后,检查输出 JSON 是否包含
"table_definition"字段;若只有"mysql_version"没有表结构,说明 SDI 区域已被擦除(如曾执行过TRUNCATE或强制DISCARD TABLESPACE)
从 JSON 提取建表语句的实操要点
输出的 JSON 不是 SQL,需要人工提取字段、类型、索引等信息拼成 CREATE TABLE。别指望自动转换——ibd2sdi 不生成完整语句,只给原始定义片段:
-
"columns"数组里每个对象含"name"、"type"、"length"、"is_nullable",注意"type": "varchar"对应 MySQL 的VARCHAR(255),但"length"值可能为 -1(表示最大长度),得按实际业务补全 -
"indexes"中"type": "PRIMARY"对应主键,"type": "INDEX"是普通索引,但不包含KEY_BLOCK_SIZE或COMMENT等扩展属性 - 外键、分区、字符集等信息藏在
"options"字段里,例如"collation": "utf8mb4_0900_ai_ci"必须显式写进CREATE TABLE的DEFAULT CHARSET和COLLATE子句 - 别漏掉
ENGINE=InnoDB ROW_FORMAT=Dynamic—— 这是 8.0 默认值,但手动建表时必须声明,否则后续ALTER TABLE ... IMPORT TABLESPACE会失败
重建表后如何安全挂载原 .ibd 数据
光有表结构不够,还得让 MySQL 把原 .ibd 文件识别为该表的数据文件。这步极易出错:
- 先用正确 DDL 创建空表(
CREATE TABLE),确保库名、表名、字段顺序、类型、引擎、ROW_FORMAT 完全一致 - 执行
ALTER TABLE xxx DISCARD TABLESPACE;—— 这会删掉新表当前的.ibd,腾出空间 - 把原始完好的
.ibd文件拷贝到数据目录对应位置,chown mysql:mysql xxx.ibd,权限必须是 mysql 用户所有 - 执行
ALTER TABLE xxx IMPORT TABLESPACE;—— 若报错Tablespace is not empty,说明.ibd里存的 space_id 和当前表不匹配,需用innodb_space工具修复,但该工具非官方,风险高,慎用 - 最后验证:查
SELECT COUNT(*)和几条记录,确认行数和内容无损;别跳过CHECK TABLE xxx;,它能发现页校验失败等底层问题
最易被忽略的是:ibd2sdi 解析出的字段顺序,未必等于你 CREATE TABLE 时写的顺序——MySQL 内部按定义顺序存储列,顺序错一个,IMPORT TABLESPACE 就会读出乱码或崩溃。务必对照 JSON 里的 "columns" 数组索引顺序来写 DDL。


















