近期一个项目在运行过程中数据库经常出现Incorrect key file for table 'xxx.MYI'; try to repair it. MySQL Errno: 126
的错误,导致项目完全无法正常运行。业主急死,打了十几个电话过来,被迫在下班的路上继续加班:joy:。
首先通过搜索找到了这两种可能性:
- 一种可能的原因是您的查询获取的数据大于您的/tmp文件夹(即用于存储临时表的文件夹)的大小。解决方法是更改/tmp文件夹的位置,或者增加/tmp文件夹的空间。
- 另一种可能的原因是表损坏。解决方法是重新创建或修复损坏的表,可以使用DROP/CREATE命令或REPAIR TABLE命令。
通过检查,我的/tmp
目录空间充足,表损坏也确实可以通过REPAIR TABLE
修复,但修复后再运行一段时间,表会再次损坏,如此往复,非常奇怪。
于是,这次我提取出了产生报错的.MYI文件,执行myisamchk
后提示该文件有以下错误:
myisamchk: warning: Table is marked as crashed
myisamchk: warning: 1 client is using or hasn't closed the table properly
这就好办了,问题应该是MySQL进程因某些原因而被意外杀掉所导致的,通过调阅服务器的监控日志,确实有一段时间有另一个运行在同一个服务器的项目的定时任务会长时间占用资源,导致内存不足,由于没有更详细的进程历史数据,这里无法百分百确定是MySQL进程被杀掉了,但大概率是这样(可以通过执行dmesg -T
查看是否出现了OOM,我这边由于已经通过监控判断到内存不足,且运维执行指令需要报备比较麻烦,就没有去操作了)。
而且,我发现这套项目比较老,数据表使用的是MyISAM
引擎,而不是现在常用的InnoDB
引擎。当mysqld
进程被杀掉时,InnoDB
引擎的崩溃恢复机制可以利用redo log
和undo log
来修复数据的损坏。而MyISAM
引擎没有这样的机制,所以反映出来的结果就是表损坏,需要手动修复才可以使用。
InnoDB引擎可以在数据库异常终止后,通过
redo log
和undo log
来恢复数据的一致性。redo log
记录了事务对数据的修改,用于在崩溃后重做已提交的事务。undo log
记录了事务对数据的逆向修改,用于在崩溃后回滚未提交的事务。
综上,内存OOM也有可能导致Incorrect key file for table
问题反复出现。
通过向另一个项目团队反馈情况后,他们对定时任务做了修改,没有再出现内存爆满的情况,我也顺便把这些数据表转成了InnoDB
引擎,问题解决。
发表回复