2026-09-27 · 约 7 分钟
Database page corruption、Page checksum mismatch、failed file read of page、space=0 page number=...。根因多为掉电/宕机造成 torn page、存储坏块、双写缓冲未生效、误删 ibdata/.ibd/日志。
立即停写,只读副本保存 /var/lib/mysql、binlog、错误日志;不要对运行中实例直接拷贝,不要删 binlog;用 CHECK TABLE、SHOW ENGINE INNODB STATUS 定位坏页。
1=跳过坏页、2=停后台线程、3=不回滚、4=不做 change buffer merge(可能永久损坏)、5=不读 undo、6=不做 redo 前滚。官方明确 4+ 可永久损坏。能从 ≤3 导出就相对安全,启动成功立即 mysqldump 分库导出再重建。
undrop-for-innodb / Percona 工具适用于 DROP/TRUNCATE、删行、.ibd/ibdata 损坏:stream_parser 归类页 → sys_parser 重建 DDL → c_parser 解析记录。必须在离线副本上运行,不保证 完整恢复。
多数可以。页损坏通常只是部分页,先固证再分级导出,核心表恢复率较高。切勿反复 force_recovery 试错。
尽量 ≤3 级;4 级及以上可能永久损坏,必须在副本上由有经验工程师操作。
binlog 闪回(binlog2sql/MyFlash)或 undrop 页解析可找回,前提 binlog 保留完整且磁盘未覆盖。
固证 + 分级启动 + 多源拼接通常 1-3 个工作日。免费检测。企业可签保密协议。
InnoDB 的页结构是固定的,所以"表被 DROP 了还能不能找回"其实有明确答案: 只要 .ibd 文件还在、页没被复用,就能按页头把记录重新解析出来,不需要 DDL。
| 项目 | 取值 / 位置 | 说明 |
|---|---|---|
| 页大小 | 默认 16KiB(innodb_page_size 可设 4K/8K/16K/32K/64K) | 所有页偏移按页号 × 页大小换算 |
| 页类型索引页 | FIL_PAGE_INDEX = 17855(0x45BF) | 定位数据页的主依据 |
| 页头位置 | 页内偏移 38 字节开始,共 56 字节 | 含页号、上一层/下一层页号、记录数 |
| 页目录 | 页尾向前,槽位数在页头 FIL_PAGE_N_DIR_SLOTS | 按槽位遍历记录,比顺序扫更准 |
| 行记录头 | 5 字节,含记录类型与下一条记录相对偏移 | 删除标记在这一层,不在页头 |
| LSN | 页头偏移 16 字节,8 字节 | 判断页的新旧,redo 回放到哪一页 |
| SDI | MySQL 8 起每表空间内含序列化字典信息 | ibd2sdi 可直接读出表结构,不必有 .frm |
# 直接读出表结构(MySQL 8 的 .ibd 自带 SDI)
ibd2sdi /cases/mysql/orders.ibd | head -40
# 看页头:页类型、记录数、LSN
python3 - <<'EOF'
d = open('/cases/mysql/orders.ibd','rb').read(16384)
import struct
print('page_type', struct.unpack('>H', d[24:26])[0])
print('n_recs', struct.unpack('>H', d[54:56])[0])
print('lsn', struct.unpack('>Q', d[16:24])[0])
EOF
# 用 mysqlfrm / undrop 类工具在副本上重建 DDL 与导出行(只读打开副本)
DROP TABLE 之后 InnoDB 会删除 .ibd 并把页标记为空闲,但只要没有新数据写入这些页, 内容就还在。真正致命的不是 DROP,而是随后的批量写入——所以第一件事永远是把 整个数据目录做镜像,而不是在原库上装工具试探。
参数判定、镜像方案、固件损坏这类问题,聊清楚不收钱;需要现场检测、书面报价或上门,统一走 项目1 服务页(到店免费检测,出报告后报价,不出结果不收费)。
18620311365
深圳市福田区深南中路2070号电子科技大厦A座35楼D22(华强北地铁站D1口步行320米)