frm与ibd文件不一致是物理备份恢复后索引“看似存在、实则失效”的核心原因,因frm仅描述结构,真实索引元数据和B+树全在ibd中;版本、校验或事务状态错位会导致EXPLAIN不走索引、Cardinality为NULL等现象。

frm 文件与数据文件(ibd 或 MYI)不一致,是物理备份恢复后索引“看似存在、实则失效”的核心原因之一——尤其在直接拷贝文件(如 rsync / cp)方式恢复 InnoDB 表时,frm 仅描述表结构,而真实索引元数据和 B+ 树结构全在 ibd 中;若两者版本、校验或事务状态错位,MySQL 会加载 frm 显示索引定义,但执行计划里 EXPLAIN 不走索引、SHOW INDEX 的 Cardinality 为 NULL 或 0。
检查 frm 和 ibd 是否匹配(InnoDB)
frm 文件本身不存索引统计,它只告诉 MySQL “这个表有这些列、哪些是索引”,真正决定索引是否可用的是 ibd 文件中 InnoDB 存储引擎层的元数据(如 SYS_INDEXES 系统表快照)与 B+ 树页的物理一致性。恢复后常见脱节表现:
-
SHOW CREATE TABLE t能看到KEY idx_x (x),但SHOW INDEX FROM t中该索引的Cardinality列是NULL -
SELECT COUNT(*) FROM t返回正确行数,但WHERE x = ?查询type: ALL -
INFORMATION_SCHEMA.STATISTICS中该索引的INDEX_TYPE是BTREE,但SEQ_IN_INDEX顺序错乱或缺失
验证步骤:
- 确认
ibd文件修改时间是否早于frm(说明frm是新生成的,ibd是旧备份,极大概率不兼容) - 运行
mysqlcheck -s db t:若报error : Incorrect information in file: './db/t.frm'或Table is marked as crashed,说明文件头校验失败 - 查看错误日志是否有
InnoDB: Error: table 'db/t' does not exist in the InnoDB internal data dictionary——这是最明确的不匹配信号
为什么 ALTER TABLE ... ENGINE=InnoDB 有时不修复
这个语句本质是触发隐式重建:先读取 ibd 数据页 → 生成新 ibd → 重写索引 B+ 树。但它依赖当前 ibd 可被 InnoDB 正确解析。若原 ibd 已损坏(如页校验失败、LSN 断层、未提交事务残留),MySQL 会跳过部分索引页重建,导致新 ibd 中索引结构残缺。
- 不要只执行
ALTER TABLE t ENGINE=InnoDB,必须加FORCE:ALTER TABLE t FORCE强制全量重建(包括重新解析所有行、重建所有索引页),绕过损坏页跳过逻辑 - 对大表,优先用
mysqldump --single-transaction导出再导入,而非物理拷贝 —— 它天然规避frm/ibd版本错配问题
MyISAM 下 .frm 与 .MYI 不一致的特殊处理
MyISAM 的索引完全独立存在 .MYI 文件中,frm 仅存结构定义。恢复时若只复制了 .MYD(数据)和 frm,漏掉 .MYI,或 .MYI 文件损坏,就会出现:
-
SELECT * FROM t WHERE key_col = ?返回空或错误:Incorrect key file for table 't'; try to repair it -
myisamchk -s t.MYI报key block size mismatch或record delete-link chain corrupted
此时不能靠 ALTER TABLE,必须用专用工具:
- 先停写:确保无客户端连接该表,或锁表
FLUSH TABLES t WITH READ LOCK - 运行
myisamchk -r -v /var/lib/mysql/db/t.MYI(-r是强制修复,-v显示过程) - 修复后立即执行
FLUSH TABLES,否则 MySQL 缓存的旧索引描述符仍生效
物理恢复不是“把文件放回目录就完事”。frm 是说明书,ibd/MYI 才是实物;说明书对不上实物,系统就只能按说明书“假装有索引”,但根本没法用。真正可靠的恢复,永远以存储引擎层的一致性为第一判断依据,而不是看 DDL 是否显示正常。


















