暂无图片
暂无图片
1
暂无图片
暂无图片
暂无图片

MySQL 表损坏修复

扫地僧的故事 2020-08-16
7688
这周给自己放了个假,每天不好好学习技术,光去研究楚国800年,秦始皇是不是死于非命了。。
但是,在大家的督促下,我又来更新了!
上周,在单位里写数据库应急预案的文档,看到同事之前写的MySQL表损坏应急处理的相关内容。之前都没怎么了解过这块内容,所以就去网上搜了下,看了看官方文档,想着简单整理了一下。
导致MySQL表损坏的几种常见原因:1.磁盘故障;2.服务器故障,异常关机等;3.mysql bug等。

不同存储引擎的表修复的方式也不一样。

对于MyISAM表,如果mysqld已经宕掉,且无法启动,那么可以通过mysiamchk工具来进行修复。如果mysqld仍在运行,或者可以重新启动,那么可以通过mysqlcheck工具来进行修复。

对于InnoDB表,如果只是索引部分被损坏,那么对于二级索引的损坏,可通过OPTIMIZE TABLE 命令来修复;如果是主键索引的损坏,可通过创建一张新表,将源表数据插入新表的方式来修复。如果是数据页被损坏,可以用SELECT... INTO OUTFILE 从数据库转储表等方式来修复。

然而,我实验做失败了,我既模拟不出刚刚好损坏索引页,也模拟不出刚刚好损坏数据页,只能暴力的vim 表的ibd文件,将错就错吧。。

创建测试表t_crash,并插入100条记录

update这个表(这一步好像没啥意义。。)

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

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

select * from t_crash;看看会不会报错?

结果并没有,猜到原因了吗?
因为有缓存,MySQL里怎么清缓存?Flush tables是清不掉的哦,有点麻烦,我还是直接重启下服务吧。
MySQL服务直接起不来,终于把自己搞死了。。
查看mysql-error.log

从错误日志中看到,不仅仅是一个数据页被损坏的问题了,表信息已经错乱了,数据库遇到了FATAL ERROR,挂掉了。根据error_log提示,打开链接:https://dev.mysql.com/doc/refman/5.7/en/forcing-innodb-recovery.html。

官方说,可以用innodb_force_recovery参数,来强制InnoDB 存储引擎启动,同时阻止后台操作运行,以便你能转储你的表。 
WARNING:
只有在紧急情况下将innodb_force_recovery设为大于0的值,你才能启动InnoDB并转储表。在进行此操作之前,确保你有数据库的备份副本,以备需要重建它。4及以上的值可以永久破坏数据文件。只有在数据库的独立物理副本的成功地测试了设置,才能在生产服务器实例使用4及以上的innodb_force_recovery设置。当强制InnoDB恢复,你应该总是以innodb_force_recovery=1启动,且仅在需要时增加值。
innodb_force_recovery 的六种模式:
  • 1 (SRV_FORCE_IGNORE_CORRUPT)

即使服务器检测到一个损坏的页,也让服务器运行着;试着让SELECT * FROM tbl_name 跳过损坏的索引记录和页,这样有助于转储表。

  • 2 (SRV_FORCE_NO_BACKGROUND)

阻止主线程和任何清除线程的运行。如果崩溃会在清除操作中发生,该恢复值会阻止它。

  • 3 (SRV_FORCE_NO_TRX_UNDO)

崩溃恢复后不运行事务回滚。

  • 4 (SRV_FORCE_NO_IBUF_MERGE)

阻止插入缓冲合并操作。如果它们会导致崩溃,不要做这些。不计算表统计。这个值可以永久损坏数据文件。使用这个值后,准备号删除并重建所有辅助索引。

  • 5 (SRV_FORCE_NO_UNDO_LOG_SCAN)

启动数据库时不查看undo log,InnoDB 把未完成的事务视为已提交的。这个值可以永久损坏数据文件。数据库处于只读状态。

  • 6 (SRV_FORCE_NO_LOG_REDO)

不在恢复连接中做日志前滚。这个值可能永久损坏数据文件。数据库页被留在一个陈旧的状态,这反过来又可能带给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起起来呢?睡了一觉,其实我也没想明白?但是,在整个实验的过程中,也了解了很多知识点,所以就简单写了下。
过两天去咨询下师傅,有结果了再来继续分享。。
文章转载自扫地僧的故事,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论