05.2 - Undo Log 详解
定位:Undo Log 是 InnoDB 原子性和 MVCC 的基础——记录数据的旧版本,支持回滚和历史版本读取 面试高频度:⭐⭐⭐⭐ 考查方式:Undo Log 与 MVCC 的关系、回滚过程、Purge 机制、8.0 中 Undo Log 的独立表空间
一、这是什么?为什么需要它?
是什么
Undo Log(回滚日志)记录的是数据修改前的旧版本。当事务回滚时,用 Undo Log 把数据恢复原状。当 MVCC 需要旧版本数据时,通过 Undo Log 版本链找到可见版本。
为什么需要 Undo Log?
两个核心用途:
- 事务回滚 —— 原子性保证:任何 DML 执行前,先记录旧值到 Undo Log。回滚时,从 Undo Log 中取出旧值恢复
- MVCC 快照读 —— 一致性非锁定读:通过 Undo Log 版本链找到事务应该看到的版本
核心 insight:Undo Log 解决的不是"写"的性能问题,而是"读的隔离性"和"写的原子性"问题。它本质上是一个"时光机"——让你可以读到数据的历史状态。
二、原理拆解
2.1 Undo Log 的类型
Undo Log
├── INSERT Undo Log
│ 记录插入行的主键
│ 回滚时: 根据主键 DELETE
│ MVCC 不需要: INSERT 前的状态是"不存在",其他事务看不到
│ 因此: INSERT Undo Log 在事务提交后可以立即回收
│
└── UPDATE Undo Log
记录修改行的旧版本(所有被修改的列 + 主键)
回滚时: 根据旧值恢复
MVCC 需要: 其他事务可能需要读旧版本
因此: UPDATE Undo Log 只在所有快照都不需要时回收2.2 Undo Log 与 MVCC 版本链
详细参见 **MVCC 实现原理**。
当前行: DB_TRX_ID=150, name='Tom', age=30
│
│ DB_ROLL_PTR
▼
Undo Log: trx_id=120, name='Tom', age=25 ← UPDATE 产生的旧版本
│
│ DB_ROLL_PTR
▼
Undo Log: trx_id=100, name='Tom', age=20 ← INSERT 产生的初始版本2.3 Purge 机制
为什么需要 Purge? Undo Log 不能一直保留——会产生大量垃圾数据。
Purge 规则:
- 事务提交后,其 Undo Log 可以清理
- 但如果有其他事务的 Read View 还需要某个版本→保留
- Purge 线程在后台持续运行,回收不再需要的 Undo Log
sql
-- 监控 Purge
SHOW ENGINE INNODB STATUS\G
-- 查看 HISTORY LIST LENGTH
-- 值越大 → 需要 Purge 的 Undo Log 越多
-- 如果持续增长 → Purge 跟不上事务提交速度 → 需要调优2.4 8.0 中的 Undo Log 变化
| 版本 | Undo Log 存储 | 特点 |
|---|---|---|
| 5.6 之前 | 系统表空间 (ibdata1) | 无法收缩,ibdata1 无限膨胀 |
| 5.6 - 5.7 | 可独立表空间 (undo_001, undo_002) | 可配置数量,但不可自动 truncate |
| 8.0 | 独立表空间,自动 truncate | innodb_undo_tablespaces,可自动收缩 |
三、面试视角
| 追问 | 答案要点 |
|---|---|
| Undo Log 的两个作用? | 事务回滚(原子性)+ MVCC 快照读(隔离性) |
| UPDATE Undo Log 和 INSERT Undo Log 的区别? | INSERT 回滚时删除行即可,MVCC 不需要 INSERT 的旧版本;UPDATE 需要保留旧版本供 MVCC 读取 |
| Undo Log 什么时候清理? | Purge 线程回收,条件是所有活跃事务的 Read View 都不再需要该版本 |
| Purge 跟不上怎么办? | 查看 HISTORY LIST LENGTH,调整 innodb_purge_threads 和 innodb_max_purge_lag |
| Undo Log 在 8.0 中有什么改进? | 独立 undo 表空间,自动 truncate 回收空间,不再导致 ibdata1 无限膨胀 |
📚 相关链接
- MVCC 详解:**MVCC实现原理**
- Redo Log:**Redo Log**
- 两阶段提交:**两阶段提交与崩溃恢复**
- ← 返回 **日志系统索引**