MyISAM索引损坏需先验证再修复:90%查询异常实为统计信息过期或索引未命中,应先查错误日志、运行CHECK TABLE确认真损坏,再结合ANALYZE TABLE更新统计信息或REPAIR TABLE修复,修复后必须验证Cardinality和EXPLAIN结果。

MyISAM索引损坏导致查询异常,必须先确认是否真损坏、再定位损坏类型,不能直接修——90%的“查询变慢”或“结果错乱”其实不是索引损坏,而是统计信息过期或查询条件没走对索引。
查错误日志和CHECK TABLE结果,别信表名“看起来正常”
MySQL不会主动告诉你“这个索引坏了”,只会报模糊错误,比如Incorrect key file for table、Table is marked as crashed,或者ERROR 1034/ERROR 1035。这些信号必须结合日志和诊断命令交叉验证:
- 先执行
SHOW VARIABLES LIKE '%log_error%'找到错误日志路径,再用grep -i 'crashed\|corrupt\|1034\|1035' /var/lib/mysql/your.err确认有没有对应表的崩溃记录 - 运行
CHECK TABLE tbl_name:如果返回status = OK,基本排除物理损坏;如果Msg_type = error且Msg_text含record is corrupted或key file is old,才是真损坏 - 注意:
CHECK TABLE对MyISAM只加读锁,不影响线上查询,但会暴露真实问题;若返回Msg_type = warning且提示Found 1 delete link,那只是碎片,不是损坏,该用OPTIMIZE TABLE而非REPAIR TABLE
EXPLAIN显示key为NULL或rows暴涨,不等于索引损坏
看到EXPLAIN SELECT ...里key列是NULL、rows从几百跳到百万级,第一反应不该是“索引坏了”,而应检查统计信息是否失效:
- 执行
SHOW INDEX FROM tbl_name,重点看Cardinality列:如果是NULL或0,说明优化器已放弃该索引,但索引文件本身可能完好 - 此时
ANALYZE TABLE tbl_name就能解决——它只更新统计信息,不碰物理文件,秒级完成 - 只有
ANALYZE TABLE后EXPLAIN仍不走索引,且CHECK TABLE也报错,才进入修复流程 - 别忽略
sql_mode影响:比如启用了STRICT_TRANS_TABLES,某些隐式类型转换会让索引失效,表现为“能查但慢”,实际和索引文件无关
REPAIR TABLE后查询变慢数倍?你可能没清掉旧统计信息
REPAIR TABLE返回OK只代表命令执行成功,不代表索引可用了。MyISAM修复后最常被跳过的一步就是ANALYZE TABLE:
-
REPAIR TABLE tbl_name QUICK只重建索引树,不校验数据行,修复快但Cardinality可能不准;REPAIR TABLE tbl_name EXTENDED会重算统计值,但部分版本仍需手动补ANALYZE TABLE - 修复完立刻跑
SHOW INDEX FROM tbl_name,确认Cardinality不再是NULL;再用EXPLAIN验证key是否命中、rows是否回归合理范围(比如从100万降到500) - 如果修复后
SELECT COUNT(*)比之前少很多,或UNIQUE索引字段出现重复值,说明REPAIR TABLE USE_FRM跳过了冲突行——这不是修复成功,是数据静默丢失 - 修复失败时常见
Can't create new tempfile,本质是tmpdir空间不足(临时文件tbl_name.TMD需≥原.MYD + .MYI大小),查SELECT @@tmpdir并清理空间再试
磁盘满之后表“能连上但查不出”,大概率是幽灵文件占着空间
MyISAM表损坏有近九成源于磁盘写入中断,而根本原因是磁盘100%。但df -h显示满、du -sh /var/lib/mysql/*总和却很小,这时要怀疑“已删未释放”的句柄:
- 执行
lsof +L1,找状态为DEL的mysqld进程打开的文件(尤其是ibtmp1或#sql-*开头的临时表),kill对应进程或重启mysqld释放空间 - 别在磁盘只剩几百MB时硬跑
REPAIR TABLE EXTENDED——它会生成临时文件,失败后留下半截.TMD,让后续修复更难 - 腾空间优先级:关慢日志(
SET GLOBAL slow_query_log = 'OFF')→ 清binlog(PURGE BINARY LOGS BEFORE DATE_SUB(NOW(), INTERVAL 3 DAY))→ 删/var/lib/mysql/下ibtmp1或#sql-*文件(后者需确认无长事务) - 修复前务必用
SHOW CREATE TABLE tbl_name确认引擎真是ENGINE=MyISAM——InnoDB表执行REPAIR TABLE会报Storage engine for the table doesn't support repair,纯属白忙
真正麻烦的不是修复动作本身,而是修复后没人验证UNIQUE约束是否还成立、EXPLAIN的rows是否真的降下来了——这两点漏掉,业务可能跑几天才发现数据错乱或查询雪崩。


















