游客发表

SQL数据库修复

发帖时间:2026-10-17 04:44:45

凌晨三点,据库运维群里跳出一条告警:主库的修复 data 盘掉了。我连上跳板机,据库`df -h` 显示那块 SSD 已经变成只读。修复MySQL 错误日志刷了满屏的据库 InnoDB 页校验失败。这不是修复演习,是据库生产环境。

很多人以为数据库坏了,修复重装一遍、据库把备份倒回去就完事。修复真到现场你会发现,据库备份可能是修复三天前的,binlog 又缺了一段。据库业务方在电话那头催,修复老板在群里问什么时候恢复。据库这时候能救你的,只有对 InnoDB 存储结构那点硬理解。

我做的第一件事是停掉 MySQL,把整个 datadir 冷拷贝一份到另一块盘。别在原盘上做任何写操作,这是铁律。哪怕你只是想 `chown` 一下,也可能让后续的页恢复彻底没戏。

先判断损坏层级

InnoDB 的损坏分好几层。最轻的是索引页坏,聚簇索引还在,数据能读出来,只是查询走错路。重的是系统表空间 ibdata1 里的数据字典页坏了,表结构都认不出来。最惨的是 redo log 被截断,未刷盘的脏页永远找不回来。

我见过一个案例:某电商订单库的从库磁盘满了,运维直接删了 ib_logfile0 想重启。结果 redo 断档,启动时 InnoDB 直接拒绝恢复,报“日志序列号不连续”。最后靠 `innodb_force_recovery=6` 强行拉起,再用 `SELECT ... INTO OUTFILE` 把能读的表全导出来,重建实例。丢了多少?大概四十分钟的订单。业务方自己认了。

force_recovery 不是万能药

这个参数从 1 到 6,级别越高越暴力。1 是忽略页校验,4 是不做 redo 前滚,6 直接当只读实例启动。很多人一上来就设 6,能起来就以为没事。其实 6 模式下 InnoDB 会跳过很多一致性检查,你看到的表可能缺行、索引错乱。用它只有一个目的:把数据 dump 出来,不是继续跑业务。

我习惯从 1 开始试。如果 1 能启动,先 `mysqldump` 全库。如果 1 不行,再往上加。每加一级,先看错误日志里 InnoDB 打印的“页号”和“表空间 ID”,那比盲试有用得多。

页级恢复的野路子

有一次,一张 200G 的日志表,聚簇索引根页坏了,force_recovery 到 3 都起不来。我用 `innodb_ruby` 工具直接解析 ibd 文件,把叶子页里的记录一条条抠出来,写成 CSV。慢,但数据全。这工具早就不维护了,跑在 Ruby 2.3 上,边跑边报 warning。可它救过我不止一次。

还有更土的办法:用 `strings` 命令扫 ibd 文件,配合正则捞手机号、订单号。精度差,但紧急情况下能先给业务一个大概的数字。别笑,真有人这么干过。

日常该盯什么

与其等坏了再修,不如平时把 `innodb_checksum_algorithm` 设成 crc32,硬件支持的话开销很小。每季度做一次 `innodb_force_recovery` 演练,拿从库练手。binlog 和备份的校验脚本必须跑起来,别只备份不验证。我见过太多人备份文件大小正常,恢复时才发现 gzip 解压报错。

数据库修复这事,七分靠准备,三分靠运气。那三分运气,往往决定你今晚能不能睡觉。

    热门排行

    友情链接