那天凌晨三点,我被电话吵醒,电话那头是运维老张的声音,急得像热锅上的蚂蚁:“数据库挂了,表坏了,业务全停了!”我揉了揉眼睛,打开电脑,远程连上服务器,看到MySQL报错信息里那个熟悉的“Table is marked as crashed”时,心里反而定了下来。这种场景,干了十年的DBA,谁没碰上过几回?表损坏这事儿,就像家里水管偶尔会堵一样,是MySQL运维的常态。但关键不在于它会不会坏,而在于你手边有没有趁手的工具,知不知道怎么修得又快又稳。

先说最常见的修复方法——用MySQL自带的myisamchk工具。这玩意儿是MyISAM存储引擎的亲儿子,专门处理表损坏问题。操作起来不复杂,先停掉MySQL服务,或者至少确保你要修复的表没有被占用。然后在命令行里敲:。这个“-r”参数是“修复”的意思,它会尝试重建索引、恢复数据。但要注意,myisamchk修复时会把表文件整个读一遍,如果表特别大,比如上千万行,那修复时间可能长得让人心慌。我之前修过一张1.5亿行的日志表,跑了整整四十分钟。所以,生产环境里,你得先评估一下影响范围,别一上来就莽。
如果你的MySQL版本是5.5以上,而且用的是InnoDB引擎,那情况就有点不一样了。InnoDB的修复逻辑跟MyISAM完全不同,它更依赖innodbforcerecovery这个参数。这个参数有1到6六个级别,数字越大,修复力度越强,但副作用也越大。比如设为1时,它会跳过损坏的页,尽量让数据库启动起来;设为6时,它会完全忽略日志文件,强行读取数据,但这时候你只能查询,写操作基本废了。我一般建议从1开始试,不行就往上加,但千万别直接跳到6,否则数据可能丢得更多。有一次,客户把参数设为6后,表是能查了,但发现少了三天的交易记录,那叫一个后悔。
说到实战技巧,不得不提“备份先行”这条铁律。我见过太多人,表一坏就急着修,结果修到一半发现数据越修越乱,连备份都没留。正确的做法是:先停服务,把表文件(.frm、.MYD、.MYI这些)原封不动复制一份到安全目录。这就好比医生做手术前,先给病人拍个CT留底。然后,用或者命令试试看。是MySQL自带的客户端工具,用法更友好:。它会在线修复,不影响其他表的读写。但有个坑:如果表损坏严重,这个命令可能直接报错退出,这时候你就得用前面说的myisamchk或者innodbforcerecovery了。
再讲一个容易被忽视的点——表碎片整理。很多时候,表不是真的“物理损坏”,而是索引被搞乱了,导致查询慢得像蜗牛爬,甚至误报成损坏。这种情况常见于频繁插入、删除的表。比如你有一个订单表,每天删掉半年前的数据,同时又写入新订单,久而久之,索引文件里就留下了大量“空洞”。这时候用命令,它会把表数据重新组织一遍,压缩索引空间。效果立竿见影,我优化过一张表,查询时间从30秒降到了0.5秒。但注意,OPTIMIZE会锁表,生产环境里最好挑业务低峰期跑,或者用pt-online-schema-change这种在线工具。
说到工具,不得不提Percona Toolkit里的神器——pt-table-checksum和pt-table-sync。这两个家伙是MySQL高可用场景下的救星。如果你的数据库是主从架构,主库表坏了,从库可能还完好无损。但问题是,你怎么知道从库的数据跟主库一不一样?pt-table-checksum会对比主从库的每一行数据,标记出不一致的地方。然后,pt-table-sync会根据主库的数据,精确修复从库。我有一回在凌晨三点接到报警,主库的一张订单表索引损坏,导致部分数据写不进去。我直接用pt-table-sync把从库的完整数据同步回主库,前后不到五分钟,业务恢复。这种“以好补坏”的思路,比硬修靠谱得多。
聊一个心态问题——别把修复当常态,预防才是王道。表损坏的根源,百分之八十是硬件问题:磁盘坏道、内存错误、突然断电。我见过最离谱的一次,是服务器机房的空调坏了,温度飙到45度,硬盘直接罢工。所以,定期做磁盘检查、配置UPS、做好备份策略,这些看似跟“修复”无关的事,其实比任何修复技巧都管用。我的习惯是,每周跑一次,每个月做一次全量备份,每季度做一次恢复演练。别嫌麻烦,等你真遇上表损坏那天,你会发现,最有用的不是修复命令,而是那份完好无损的备份文件。


