undo log 写入发生在事务执行阶段,早于 redo log prepare;它在dml语句执行时即同步写入undo log buffer,是修改流程的第一步,为回滚和mvcc提供前镜像并确保崩溃恢复时undo链完整。

Undo Log 写入发生在事务执行阶段,早于 Redo Log Prepare
Undo Log 的写入不是等到事务提交才发生,而是在 UPDATE、DELETE 或 INSERT 这类 DML 语句真正执行时就立即写入内存的 Undo Log Buffer。它比 Redo Log 的 prepare 阶段更早,是整个修改流程的第一步。
常见错误现象:有人看到 SHOW ENGINE INNODB STATUS 中 “undo log records” 数量增长滞后,误以为 Undo Log 是提交时才写;其实只是刷盘(到磁盘 Undo 表空间)异步延迟,写入内存是同步且前置的。
- 执行
UPDATE users SET balance = 200 WHERE id = 1时,InnoDB 先从 Buffer Pool 读取该行,再把原值(比如balance=100)写入Undo Log Buffer - 这个动作和后续修改 Buffer Pool 数据页、写入
Redo Log Buffer是原子性串联的——Undo 必须先记,才能保证回滚有据可依 -
TRX_UNDO_INSERT类型(来自 INSERT)在事务提交后立刻释放;TRX_UNDO_UPDATE类型(来自 UPDATE/DELETE)则保留在内存+磁盘,供 MVCC 使用,直到 purge 线程清理
为什么 Undo Log 必须在 Redo Log Prepare 之前写入?
因为 Redo Log 记录的是“物理变更”,而 Undo Log 提供的是“逻辑前镜像”。InnoDB 在生成 Redo Log 时,会把 Undo Log 页的修改也一并记录进去(即 Undo 操作本身也要被 redo 保护),所以 Undo Log 的分配和初始化必须先行完成。
如果顺序颠倒——比如先写 Redo Log 再写 Undo Log——那崩溃恢复时可能拿到一个不完整的 Undo 链,导致回滚失败或 MVCC 读取到错误版本。
- 事务开始时,InnoDB 会为它分配一个回滚段 slot,并初始化第一个
Undo page header - 每次写入新 Undo record 前,都要更新
roll_pointer和trx_id隐藏字段,这些操作本身会产生 Redo Log - 因此,Undo Log 的写入不仅是用户可见的“记录旧值”,更是底层存储结构初始化的关键环节
容易被忽略的刷盘时机差异
很多人混淆“写入内存”和“持久化到磁盘”——Undo Log 的内存写入是即时的,但刷盘到 Undo 表空间(如 undo_001.ibu)是异步的,由后台线程控制,不受 innodb_flush_log_at_trx_commit 影响。
这导致一个典型问题:长事务未提交时,Undo Log 在内存中持续增长,但磁盘上看不到对应文件膨胀;而一旦事务提交,TRX_UNDO_UPDATE 类型的记录又不会马上删除,而是挂入 history list,等待 purge 线程回收——此时磁盘空间才真正开始缓慢释放。
- 检查 Undo 空间压力,不能只看
information_schema.INNODB_METRICS中的undo_log_records_added,更要关注history_list_length -
innodb_max_undo_log_size控制单个 Undo 表空间大小上限,但 purge 延迟会导致实际占用远超该值 - 若发现
purge lag持续上升,说明历史版本堆积,MVCC 快照读性能会下降,甚至触发ERROR 1205 (HY000): Deadlock found when trying to get lock











