mysql崩溃恢复必须用redo log而非binlog,因为redo log是物理日志,精确记录页级字节变更(如“第123页偏移45处从0x01改为0x0a”),支持启动时严格按lsn顺序前滚重放;而binlog是逻辑日志,仅记录sql语句,无页上下文、不保证刷盘、无法安全重放损坏数据页。

崩溃恢复只靠 REDO LOG,BINLOG 完全不参与。 这不是配置问题,而是设计使然:InnoDB 启动时只会读 ib_logfile0 和 ib_logfile1 做前滚(redo),根本不会碰 mysql-bin.* 文件。
为什么崩溃恢复必须用 REDO LOG 而不能用 BINLOG
REDOL OG 是物理日志,记录的是「第 123 号页、偏移 45 字节、从 0x01 改成 0x0A」这种精确到字节的变更;BINLOG 是逻辑日志,只记 UPDATE user SET age = 25 WHERE id = 1 这种语句。崩溃后数据页可能只写了一半,靠 SQL 重放会出错——比如页没加载、索引结构已损坏、甚至 WHERE 条件匹配到错误行。
常见错误现象:innodb_flush_log_at_trx_commit=0 下 MySQL 掉电重启,大量已提交事务丢失——这不是 BUG,是主动放弃 REDO LOG 持久性保障的结果。
- REDOL OG 强制刷盘(受
innodb_flush_log_at_trx_commit控制),且校验 LSN(日志序列号)连续性,启动时严格按顺序重放 - BINLOG 默认异步写入 OS 缓存,
sync_binlog=0时掉电即丢;即使设为 1,它也不记录页级上下文,无法保证重放安全 - 手动删掉
ib_logfile*会导致 MySQL 启动失败,报错The log sequence number in ibdata files does not match;而删mysql-bin.*只影响主从和备份,不影响单机恢复
REDO LOG 崩溃恢复的实际流程
MySQL 启动时,InnoDB 不是从 ibdata1 或表空间文件“重新读数据”,而是先检查 REDO LOG 文件头,定位最后有效 LSN,然后逐条重放所有已提交但尚未刷入数据页的物理修改——这个过程叫「前滚」(Redo Phase)。
重放完成后,再进入「回滚阶段」(Undo Phase),用 UNDO LOG 把未提交事务的脏页改回去。这两个阶段顺序不可逆,且都只依赖 REDO + UNDO,与 BINLOG 无关。
- 重放单位是 Mini-Transaction(MTR),保证页分裂、索引更新等复合操作原子性
-
innodb_log_file_size太小 → checkpoint 频繁 → 写入抖动;太大 → 崩溃后前滚耗时久(可能数分钟) - 恢复时间取决于 REDO LOG 中待重放的字节数,跟 BINLOG 文件大小或位置完全无关
BINLOG 在什么场景下才真正起作用
BINLOG 不用于崩溃恢复,但它在误操作恢复、主从同步、时间点还原中不可替代。例如误删整张表,ROLLBACK 无效(已提交),ib_logfile 也帮不上忙(循环覆盖、无 SQL 语义),唯一能救回来的就是 BINLOG。
- 恢复前提:必须开启
log_bin=ON,且格式为ROW或MIXED - 关键命令:
mysqlbinlog --base64-output=DECODE-ROWS -v mysql-bin.000012查看被删的原始行 - 切勿直接
mysqlbinlog xxx | mysql,里面可能含DROP TABLE,会二次破坏结构 - 用
--start-position或--exclude-gtids精确跳过坏操作,再导入
最容易被忽略的一点:REDOL OG 和 BINLOG 的协同靠两阶段提交(2PC),但这个机制只在事务提交时保证二者逻辑一致;一旦崩溃发生,InnoDB 就彻底“忘记” BINLOG,只认自己的物理日志。指望 BINLOG 救崩溃,就像拿监控录像去修坏掉的硬盘——方向就错了。











