结论:ibdata1损坏不可修复,需放弃原地修复,转而通过.frm解析建表、DISCARD/IMPORT TABLESPACE挂载.ibd文件恢复数据;错误日志无“Corrupted page”但SHOW TABLES为空、information_schema无记录,即为数据字典损毁。

直接说结论:系统表空间(ibdata1)损坏时,innodb_force_recovery 大概率无效,必须放弃“原地修复”幻想,转向基于 .frm + .ibd 文件的结构重建与表空间导入导出流程。
先确认是不是真的 ibdata1 损坏,而不是单个 .ibd 文件丢失
断电后常见假象是“很多表查不到”,但真正元数据层损坏的表现更隐蔽:SHOW DATABASES 能看到库名,USE db_name 成功,但 SHOW TABLES 返回空,或执行 SELECT * FROM information_schema.tables WHERE table_schema = 'db_name' 无结果。错误日志里反复出现 Tablespace is missing for table 或 Failed to open table,但没有 Corrupted page found —— 这说明数据字典本身已不可读,不是某张表的 .ibd 坏了,而是 ibdata1 里存的系统表(如 mysql.innodb_table_stats、information_schema 视图元数据)已损毁。
- 别急着改
innodb_force_recovery:它只对 InnoDB 引擎层恢复有效,对ibdata1中的数据字典损坏基本无能为力 - 用
strings ibdata1 | head -50看是否还能提取出可读的表名或库名片段;如果全是乱码或空输出,基本确认元数据区被覆写 -
mysqlcheck --all-databases --check会大量报Table 'db.t' doesn't exist,这不是权限问题,是字典缺失
用 mysqlfrm 解析 .frm 文件重建表结构
.frm 文件独立于 ibdata1,只要文件没被覆盖,就能从中还原建表语句——这是抢救的核心突破口。注意 MySQL 5.7+ 的 .frm 是二进制格式,必须用对应版本的 mysqlfrm(来自 MySQL Utilities)解析,否则会报 Unsupported .frm file version。
- 把所有
.frm文件集中到临时目录,例如/tmp/frm_dump - 运行:
mysqlfrm --server=root:@127.0.0.1:3306 --port=3434 /tmp/frm_dump/*.frm --user=mysql --diagnostic > frm.sql(--server参数仅用于连接本地空实例获取默认字符集,不依赖现有数据) - 生成的 SQL 里常含
ROW_FORMAT = 2或ROW_FORMAT = 5,这是旧版内部编码,MySQL 5.7+ 不识别,必须用sed替换掉:sed -i 's/ROW_FORMAT = [0-9]//g; s/, $//; s/,$//' - 去掉
CREATE DATABASE和USE语句,只保留CREATE TABLE,避免创建冲突
构造 DISCARD/IMPORT TABLESPACE 流程批量挂载 .ibd 文件
表结构建好后,.ibd 文件仍处于“游离”状态,需强制关联。关键点在于:必须确保新表的 table_id 与原 .ibd 文件头里的 ID 一致,否则 IMPORT 会静默失败(无报错但数据查不到)。
- 先在干净 MySQL 实例中执行
CREATE TABLE语句,再立刻执行:ALTER TABLE t DISCARD TABLESPACE,释放新分配的table_id - 用
dbsake ibdscan /path/to/t.ibd查看原.ibd的table_id,若不匹配,需用ibd2sql提取数据而非直接导入 - 批量生成语句:
mysql -N -e "SELECT CONCAT('ALTER TABLE ', table_name, ' DISCARD TABLESPACE;') FROM information_schema.tables WHERE table_schema='recovery_db'" > discard.sql - 复制
.ibd文件到新实例的datadir/recovery_db/下,chown mysql:mysql *.ibd,再执行import.sql
导出时绕过 --single-transaction,用 --lock-tables=false 配合 mysqldump
系统表空间损坏后,mysqldump 的事务一致性保障失效,--single-transaction 会卡死或跳过部分表。此时要接受“最终一致性”,优先保数据可导出。
- 启动参数中已启用
innodb_force_recovery = 1(仅用于让服务起来),但导出时不要依赖它 - 执行:
mysqldump --no-create-info --skip-triggers --skip-routines --lock-tables=false recovery_db > data.sql - 若某张表导出失败,单独处理:
mysqldump --no-create-info --skip-triggers --skip-routines --where="1=1 LIMIT 10000" recovery_db t > t_part.sql,分块导出 - 导出完成后立即停库,注释掉
innodb_force_recovery,切勿长期带该参数运行
整个过程最易被忽略的是 .frm 与 .ibd 的版本兼容性——MySQL 5.6 的 .frm 无法被 8.0 的 mysqlfrm 正确解析,而 8.0 的 .ibd 文件头结构又和 5.7 不同。断电前用的是哪个版本,就得用那个版本的工具链,混用只会得到空表或乱码字段。


















