这周给自己放了个假,每天不好好学习技术,光去研究楚国800年,秦始皇是不是死于非命了。。上周,在单位里写数据库应急预案的文档,看到同事之前写的MySQL表损坏应急处理的相关内容。之前都没怎么了解过这块内容,所以就去网上搜了下,看了看官方文档,想着简单整理了一下。导致MySQL表损坏的几种常见原因:1.磁盘故障;2.服务器故障,异常关机等;3.mysql bug等。不同存储引擎的表修复的方式也不一样。
对于MyISAM表,如果mysqld已经宕掉,且无法启动,那么可以通过mysiamchk工具来进行修复。如果mysqld仍在运行,或者可以重新启动,那么可以通过mysqlcheck工具来进行修复。
对于InnoDB表,如果只是索引部分被损坏,那么对于二级索引的损坏,可通过OPTIMIZE TABLE 命令来修复;如果是主键索引的损坏,可通过创建一张新表,将源表数据插入新表的方式来修复。如果是数据页被损坏,可以用SELECT... INTO OUTFILE 从数据库转储表等方式来修复。
然而,我实验做失败了,我既模拟不出刚刚好损坏索引页,也模拟不出刚刚好损坏数据页,只能暴力的vim 表的ibd文件,将错就错吧。。
创建测试表t_crash,并插入100条记录


接着,vim编辑t_crash.ibd,原t_crash.ibd文件,右下角为629d:

修改后的t_crash.ibd文件,右下角改成了627d:

select * from t_crash;看看会不会报错?
因为有缓存,MySQL里怎么清缓存?Flush tables是清不掉的哦,有点麻烦,我还是直接重启下服务吧。
从错误日志中看到,不仅仅是一个数据页被损坏的问题了,表信息已经错乱了,数据库遇到了FATAL ERROR,挂掉了。根据error_log提示,打开链接:https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html。
官方说,可以用innodb_force_recovery参数,来强制InnoDB 存储引擎启动,同时阻止后台操作运行,以便你能转储你的表。 只有在紧急情况下将innodb_force_recovery设为大于0的值,你才能启动InnoDB并转储表。在进行此操作之前,确保你有数据库的备份副本,以备需要重建它。4及以上的值可以永久破坏数据文件。只有在数据库的独立物理副本的成功地测试了设置,才能在生产服务器实例使用4及以上的innodb_force_recovery设置。当强制InnoDB恢复,你应该总是以innodb_force_recovery=1启动,且仅在需要时增加值。innodb_force_recovery 的六种模式:即使服务器检测到一个损坏的页,也让服务器运行着;试着让SELECT * FROM tbl_name 跳过损坏的索引记录和页,这样有助于转储表。
阻止主线程和任何清除线程的运行。如果崩溃会在清除操作中发生,该恢复值会阻止它。
崩溃恢复后不运行事务回滚。
阻止插入缓冲合并操作。如果它们会导致崩溃,不要做这些。不计算表统计。这个值可以永久损坏数据文件。使用这个值后,准备号删除并重建所有辅助索引。
启动数据库时不查看undo log,InnoDB 把未完成的事务视为已提交的。这个值可以永久损坏数据文件。数据库处于只读状态。
不在恢复连接中做日志前滚。这个值可能永久损坏数据文件。数据库页被留在一个陈旧的状态,这反过来又可能带给B-trees和其它数据库结构更多的损坏。数据库处于只读状态。
设置innodb_force_recovery =1,启动数据库,依旧起不来。。(预料之中,因为我损坏的不仅仅是数据页。。)
设置innodb_force_recovery =4,启动数据库,虽然有一堆ERROR,但是数据库服务起来了!

再去select被损坏的表,报错:ERROR 1812:Tablespace is missing for table XXX。出现ERROR 1812的几种可能情况:1.数据文件的用户属组或权限错误 ; 2.数据文件的路径错误;3.数据文件损坏或者被删了很显然,现在是数据文件被损坏,不可能有什么转储表这种操作了,为了让数据库服务正常启动,我先把这个表删除了,之后再通过备份恢复回来。
设置innodb_force_recovery =0,重启数据库,MySQL服务运行正常。
昨天晚上,文章写到一半,写不下去了,一直在纠结一个问题,如果主库发生了表损坏的情况,直接主备切换下,备库对外提供服务不就好了吗?干嘛还非要设置innodb_force_recovery,强制把innodb起起来呢?睡了一觉,其实我也没想明白?但是,在整个实验的过程中,也了解了很多知识点,所以就简单写了下。