redo log / undo log / binlog 区别

一句话总结

redo log 保”持久性”(崩溃后数据不丢),undo log 保”原子性”(失败能回滚到之前的样子),binlog 保”备份和同步”(主从复制和恢复)。三个日志分工不同,缺了谁 MySQL 都可能丢数据或崩了修不回来。


🌰 三兄弟各司其职

你在一家银行柜台转账:

 
你填了一张转账单:从 A 账户转 1000 到 B 账户。
 
银行操作:
 
  1. 在账本上写"准备从 A 扣 1000"  →  undo log(万一转一半崩了,改回来)
 
  2. 在账本上写"从 A 扣 1000"      →  redo log(已执行,崩了也能恢复)
 
  3. 在 A 账户上真的扣掉 1000
 
  4. 在账本上写"准备给 B 加 1000"  →  undo log
 
  5. 在账本上写"给 B 加 1000"      →  redo log
 
  6. 在 B 账户上真的加上 1000
 
  7. 在流水账本上写"今天发生了什么" →  binlog(给会计对账、复制到分店用的)
 
日志角色类比
undo log后悔药——失败了能回退操作前的备份小纸条
redo log保险箱——崩了不丢数据操作后的钢印记录
binlog流水账——给其他人看的银行的日终对账单

一、redo log——“我干了什么”

二、undo log——“我准备改之前是什么样”

三、binlog——“整个数据库发生了什么”

本质

物理日志,记录的是”对哪个数据页的哪个偏移量做了什么修改”。

 
redo log 记录的内容(概念上):
 
  把表空间 X 的页号 5 的偏移量 1024 处的值改为 1000
 

为什么需要 redo log?

 
UPDATE user SET balance = 1000 WHERE id = 1;
 

MySQL 不会直接改磁盘上的数据(太慢了)。流程是:

 
1. 把 id=1 的数据页加载到内存(Buffer Pool)
 
2. 在内存里把 balance 改成 1000
 
3. 写 redo log(记录"页 5 偏移 1024 改成 1000")
 
4. (先不写磁盘,标记为"脏页")
 
5. 返回"更新成功"给客户端
 
6. 空闲时再把脏页刷回磁盘
 

如果第 5 步之后、第 6 步之前停电了:

  • 内存里的数据没了(balance=1000 丢了)

  • 但 redo log 在磁盘上

  • 重启后 MySQL 重放 redo log → 数据恢复

redo log 保证了 Crash Safe(崩溃安全)。只要写了 redo log 并提交了,数据就不会丢。

redo log 的两阶段提交

这是 MySQL 保证 redo log 和 binlog 一致性的关键机制:

 
事务提交时:
 
  1. 写 redo log(Prepare 阶段)
 
  2. 写 binlog
 
  3. 写 redo log(Commit 阶段)
 
如果在 1-2 之间崩了 → redo log 是 Prepare 状态,binlog 没有 → 回滚
 
如果在 2-3 之间崩了 → redo log 是 Prepare 状态,binlog 有 → 提交(保证 binlog 和 redo 一致)
 

本质

逻辑日志,记录的是”修改之前的数据是什么”,用于回滚和 MVCC。

 
undo log 记录的内容(概念上):
 
  UPDATE user SET balance = 1000 WHERE id = 1
 
  之前的 balance = 500
 

两个作用

作用 1:事务回滚

 
BEGIN;
 
UPDATE user SET balance = 1000 WHERE id = 1;
 
-- 写 undo log:记录 id=1 的 balance 原来是 500
 
UPDATE user SET balance = 2000 WHERE id = 2;
 
-- 写 undo log:记录 id=2 的 balance 原来是 1500
 
ROLLBACK;
 
-- 从 undo log 里读出旧值:balance 500 和 1500
 
-- 把数据改回去
 

没有 undo log,ROLLBACK 就不知道改回什么。

作用 2:MVCC 多版本并发控制

 
-- 事务 A(未提交):UPDATE user SET balance = 1000 WHERE id = 1
 
-- 事务 B(正在查询):SELECT balance FROM user WHERE id = 1
 

事务 B 需要看到旧值(500),新值(1000)还没提交。

每个事务通过 undo log 构建自己”可见”的数据版本。 这就是 MVCC 的”多版本”——不是真的存了多个副本,而是通过 undo log 可以反向计算出旧版本。

undo log 的生命周期

 
事务执行中:undo log 一直保留
 
事务提交后:undo log 不能立即删除
 
  └─ 还有别的事务可能通过 MVCC 在读取旧版本
 
  └─ 等所有需要这个版本的事务都结束了 → purge 线程清理
 

本质

逻辑日志,记录的是”执行了什么 SQL”或”每一行怎么变的”。

 
binlog 记录的内容(概念上):
 
  UPDATE user SET balance = 1000 WHERE id = 1  -- STATEMENT 模式
 

 
  把 id=1 的 balance 从 500 改成 1000            -- ROW 模式
 

和 redo log 的区别

redo logbinlog
所属层级InnoDB 引擎层MySQL Server 层
属于哪个引擎只有 InnoDB 有所有引擎都有(MyISAM 也有)
日志类型物理日志(改了哪个页的哪个字节)逻辑日志(执行了什么 SQL/行变更)
写入时机事务执行中持续写入事务提交时一次性写入
存储固定大小,循环写(写满覆盖旧记录)追加写,可以一直保留
用途崩溃恢复 + Crash Safe主从复制 + 时间点恢复

binlog 的主要用途

1. 主从复制

 
主库写 binlog → 从库拉 binlog → 从库重放 → 数据一致
 

2. 时间点恢复(Point-in-Time Recovery)

 
-- 每天凌晨备份一次
 
mysqldump ...
 
-- 下午 3 点误删了表
 
-- 恢复流程:
 
-- 1. 导入凌晨的备份
 
-- 2. 重放从凌晨到下午 3 点的 binlog
 
-- 3. 跳过 DROP TABLE 那条 SQL
 

binlog 的三种格式

格式记录方式优点缺点
STATEMENT记录原始 SQL日志量小不安全(NOW 等函数在主从不一致)
ROW(推荐)记录每行的变更最安全,精确日志量大
MIXEDMySQL 自动选折中偶尔有问题

5.7+ 默认 ROW 模式。线上用 ROW,别纠结。


三张日志的执行流程(一条 UPDATE 语句)

 
UPDATE user SET balance = 1000 WHERE id = 1;
 

graph TD

    subgraph Buffer_Pool["Buffer Pool"]

        BP["id=1 的 balance=1000<br/>(内存里改了)"]

    end

    BP -.->|"1. 写 undo"| Undo["undo log<br/>(balance 原来是 500)"]

    Undo --> RedoP["2. 写 redo log<br/>(Prepare 阶段)"]

    RedoP --> Binlog["3. 写 binlog"]

    Binlog --> RedoC["4. 写 redo log<br/>(Commit 阶段)"]

    RedoC --> Success["返回'更新成功'"]


三张日志对比总结

维度redo logundo logbinlog
一句话崩了不丢数据可以回滚到之前给主从复制和对账用
日志类型物理(哪个页哪个偏移)逻辑(改之前的值)逻辑(SQL 或行变更)
所属层InnoDB 引擎InnoDB 引擎MySQL Server
写入时机执行中持续写执行中持续写提交时一次性写
存储方式循环写,固定大小事务结束后可 purge追加写,可长期保留
用途崩溃恢复回滚 + MVCC主从复制 + PITR
关了会怎样更新不持久,崩了丢数据不能回滚、MVCC 挂掉不能主从复制

记忆口诀

redo 保命(崩了恢复),undo 保悔(回滚+MVCC),binlog 保驾(主从+备份)。

redo 和 binlog 靠两阶段提交保一致——Prepare→binlog→Commit。

三条日志一条都不能少,各有各的使命,谁也替不了谁。

速记卡(面试闪卡)

Q1:一句话讲清「redo log / undo log / binlog 区别」到底是什么?

A:redo/undo/binlog 是 MySQL 三种日志:redo 保崩溃恢复,undo 保回滚+MVCC,binlog 保主从同步。

Q2:一句话总结 —— 怎么理解?

A:三兄弟各司其职:undo 是后悔药(操作前备份)、redo 是保险箱(崩了不丢)、binlog 是流水账(给分店对账)(Crash Safe 崩溃安全)。

Q3:🌰 三兄弟各司其职 —— 怎么理解?

A:银行转账最形象:先写 undo 备忘、再写 redo 钢印、最后写 binlog 流水,三份配合保证”钱不丢、能回退、可对账”(WAL 预写日志)。

Q4:一、redo log——“我干了什么” —— 怎么理解?

A:redo 像保险箱钢印:记”页5偏移1024改成1000”这种物理修改,崩了重放就恢复,保证持久性(physical log 物理日志)。

Q5:二、undo log——“我准备改之前是什么样” —— 怎么理解?

A:undo 像后悔药小纸条:记修改前的旧值,ROLLBACK 靠它回退,MVCC 靠它看历史版本(logical log 逻辑日志)。

Q6:核心速记主线有哪些?

  • redo log:物理日志,崩了重放恢复,保持久性(Crash Safe)

  • undo log:逻辑日志,回滚+MVCC 多版本,保原子性

  • binlog:逻辑日志,主从复制+时间点恢复,Server 层

  • 两阶段提交 Prepare→binlog→Commit 保证 redo 与 binlog 一致

口诀

A:redo 保命崩了恢复,undo 保悔能回滚;

binlog 保驾主从同步,流水对账不迷路;

两阶段提交保一致,Prepare binlog Commit;

三份日志各有命,谁也替不了谁。

相关链接