背景
有朋友找说他们MySQL数据库服务器重启后,实例就一直启动不了,版本MySQL5.7.28,服务器windows server2012,没有备份,没有主从,没有开启binlog,里面有分区表。
思路:
遇事首先就是查看error日志,发现里面没有error错误,只有大量的如下告警:
2022-04-25T01:12:31.873183Z 0 [Note] InnoDB: Uncompressed page, stored checksum in field1 295425355, calculated checksums for field1: crc32 3527925424, innodb 295425355, none 3735928559, stored checksum in field2 3092011775, calculated checksums for field2: crc32 3527925424, innodb 3092011775, none 3735928559, page LSN 3612 1717627711, low 4 bytes of LSN at page end 1717627711, page number (if stored to page already) 4, space id (if created with >= MySQL-4.1.1 and stored already) 351762 InnoDB: Page may be an index page where index id is 368064 2022-04-25T01:12:31.873183Z 0 [Note] InnoDB: Index 368064 is `GEN_CLUST_INDEX` in table `gps`.`data_on_off_sign_r` 2022-04-25T01:12:31.873183Z 0 [ERROR] InnoDB: Corruption of an index tree: table `gps`.`data_on_off_sign_r` index `GEN_CLUST_INDEX`, father ptr page no 897, child page no 898 PHYSICAL RECORD: n_fields 27; compact format; info bits 32 0: len 6; hex 00065bdc2541; asc [ %A;; 1: len 6; hex 0000a31fcedd; asc ;; 2: len 7; hex 4c000264a13111; asc L d 1 ;; 3: len 5; hex 3236303833; asc 26083;; 4: SQL NULL; 5: len 19; hex 323032312d31312d30362031313a34313a3133; asc 2021-11-06 11:41:13;; 6: SQL NULL; 7: SQL NULL; 8: len 9; hex e5bca0e79599e68caf; asc ;; 9: len 20; hex 3436303330303838383838383838383838383838; asc 46030088888888888888;; 10: len 20; hex 3436303330303838383838383838383838383838; asc 46030088888888888888;; 11: len 4; hex 58585858; asc XXXX;; 12: len 8; hex 5950189469fc5d40; asc YP i ]@;; 13: len 8; hex 34bbeead48ac3f40; asc 4 H ?@;; 14: len 30; hex e6b19fe88b8fe79c81e5b8b8e5b79ee5b882e6ada6e8bf9be58cba3be6ad; asc ; ; (total 169 bytes); 15: len 8; hex 0000000000000000; asc ;; 16: len 8; hex 0000000000000000; asc ;; 17: SQL NULL; 18: len 3; hex 302020; asc 0 ;; 19: SQL NULL; 20: len 4; hex 8209cae8; asc ;; 21: SQL NULL; 22: SQL NULL; 23: len 8; hex 3030303030303030; asc 00000000;; 24: len 19; hex 323032322d30342d32352030303a30303a3030; asc 2022-04-25 00:00:00;; 25: len 4; hex 824bab5c; asc K \;; 26: SQL NULL; 2022-04-25T01:12:31.873183Z 0 [Note] InnoDB: n_owned: 0; heap_no: 2; next rec: 492 PHYSICAL RECORD: n_fields 2; compact format; info bits 0 0: len 6; hex 00065bdc2509; asc [ % ;; 1: len 4; hex 00000381; asc ;;
一看日志显示就是有一个表data_on_off_sign_r的一个索引损坏了,首先怀疑是否重启服务器导致硬件损坏,然后就是表的索引块损坏。
处理:
把这个参数改为从1-6的尝试启动innodb_force_recovery = 1,如果启动了,首先是备份一下数据。然后尝试删除该表重建。
此处是在2的时候启动了,直接drop 后修改为0,启动成功。
[mysqld]
innodb_force_recovery = N
引用该参数相关的解释:
innodb_force_recovery默认为0(没有强制恢复的正常启动)。对于innodb_force_recovery允许的非零值是1至6。较大值包括较小值的功能。例如,为3的值包括所有的值1和2的功能。
如果你能以innodb_force_recovery为3或更低值转储你的表,那么你是比较安全的,只有在损坏的个人页的一些数据会丢失。4或更大的值被认为是危险的,因为数据文件可以被永久地损坏。值6被认为是严重的,数据库页被留在一个陈旧的状态,这反过来又可能带给B-trees和其它数据库结构更多的损坏。
作为一个安全措施,InnoDB 在innodb_force_recovery大于0时阻止INSERT,UPDATE或DELETE操作。对于MySQL5.6.15,将innodb_force_recovery设为4或更高会让InnoDB处于只读模式。
1 (SRV_FORCE_IGNORE_CORRUPT)
即使服务器检测到损坏的页仍让它运行。试图使SELECT* FROM tbl_name跳过损坏的索引记录和页,这样有助于转储表。忽略检查到的 corrupt 页。尽管检测到了损坏的 page 仍强制服务运行。一般设置为该值即可,然后 dump 出库表进行重建。
2 (SRV_FORCE_NO_BACKGROUND)
阻止主线程和任何清除线程的运行。如果崩溃会在清除操作中发生,该恢复值会阻止它。如主线程需要执行 full purge 操作,会导致 crash。 阻止 master thread 和任何 purge thread 运行。若 crash 发生在 purge 环节则使用该值。
3 (SRV_FORCE_NO_TRX_UNDO)
不在崩溃恢复后运行事务回滚。
4 (SRV_FORCE_NO_IBUF_MERGE)
阻止插入缓冲合并操作。如果它们会导致崩溃,不要做这些。不计算表统计。这个值可以永久损坏数据文件。使用这个值后,准备好删除并重建所有辅助索引。在MySQL5.6.15中,设置InnoDB为只读。
5 (SRV_FORCE_NO_UNDO_LOG_SCAN)
在启动数据库时不查看撤消日志:InnoDB将即使未完成的事务也作为已提交。这个值可以永久损坏数据文件。在MySQL5.6.15中,设置InnoDB为只读。
6 (SRV_FORCE_NO_LOG_REDO)
不执行前滚的操作。恢复时不做 redo log roll-forward。这个值可能永久损坏数据文件。数据库页被留在一个陈旧的状态,这反过来又可能带给B-trees和其它数据库结构更多的损坏。在MySQL5.6.15中,设置InnoDB为只读。