MyISAM的.MYI文件易丢失或损坏,因其无事务日志、无校验和、依赖裸文件I/O,断电、kill -9或磁盘满即可导致写入中断;CHECK TABLE检测浅层,可能误报OK,需结合ls、hexdump和myisamchk验证;修复后必须执行ANALYZE TABLE更新统计信息。

MyISAM 的 .MYI 文件丢失或损坏不是小概率事件,而是其存储机制决定的必然风险——它没有事务日志、不写双写缓冲、全靠操作系统级文件 I/O,一次断电、kill -9 或磁盘满就可能让 .MYI 半途而废。
MyISAM 索引文件为什么连“存在”都难保证
.MYI 是纯二进制索引结构文件,不包含校验和,也不记录自身元数据版本。MySQL 启动时只检查文件是否存在、能否 open() 和读取前几个字节头信息;一旦头损坏或文件被截断(比如写入中途磁盘满),MySQL 就直接报 Can't find file: 'xxx.MYI' (errno: 2) 或 Incorrect key file for table 'xxx',连“是否真丢了”都懒得深究。
- 它不依赖
ib_logfile那类重做日志,无法回滚未完成的索引更新 - 所有索引修改都是直接
write()到文件,无中间缓冲层兜底 -
FLUSH TABLES不强制刷.MYI,sync_binlog=1也管不到它
哪些操作会直接触发 .MYI 丢失
不是所有写操作都危险,但以下场景下 .MYI 脆弱性会被放大:
-
REPAIR TABLE xxx USE_FRM执行中被中断:该模式会先删旧.MYI,再重建,中断 = 彻底丢失 - 用
myisamchk -r离线修复时 mysqld 仍在运行:两个进程同时改同一文件,.MYI可能变成空文件或乱码 - 手动
rm *.MYI后忘记REPAIR TABLE:MySQL 不自动重建,后续任何SELECT都报错 - 从 NFS 或低可靠存储挂载数据目录:部分 NFS 实现对
fsync()模拟不完整,.MYI写入看似成功实则未落盘
为什么 CHECK TABLE 有时查不出 .MYI 丢失
CHECK TABLE 对 .MYI 的检测非常轻量:它只尝试 mmap() 或 read() 前几百字节,验证 magic number 和基本块头。如果 .MYI 文件存在但内容全零、或被覆盖成其他二进制格式(如误 cp 了 .MYD 过去),CHECK TABLE 可能返回 status = OK,但后续查询立刻崩在索引遍历阶段。
- 真正可靠的判断方式是:
ls -l table.MYI看大小是否明显异常(比如只有 0 字节或远小于历史值) - 再用
hexdump -C table.MYI | head -n 2看前几行是否为可识别的 MyISAM 索引头(通常以0x00 0x01开头,后跟版本字段) -
myisamchk --info table.MYI比CHECK TABLE更底层,能暴露 “key cache read error” 类真实 I/O 失败
别指望自动恢复,得靠人工干预链
MyISAM 没有崩溃恢复流程,.MYI 丢失后 MySQL 不会尝试重建、不报警、不记录 warning 日志——它只是在第一次访问该表时抛错。这意味着:
- 错误可能潜伏数小时甚至数天,直到某条业务 SQL 触发索引扫描才暴露
-
mysqld错误日志里往往只有单行Incorrect key file,无上下文、无堆栈、无时间戳关联 - 监控系统若只盯
Aborted_clients或慢查询,根本捕获不到这类静默故障
最易被忽略的一点:修复后即使 REPAIR TABLE 返回 OK,也必须立刻跑 ANALYZE TABLE。否则优化器仍按旧统计信息估算,EXPLAIN 看起来走索引,实际执行时因 .MYI 结构重排导致大量随机 I/O,性能反而更差。


















