SQL 日志文件(Redo / Undo)分别做什么?

8次阅读

redo日志记录物理页变更以保证持久性,崩溃后重放已提交事务;Undo日志记录逻辑前镜像以支持回滚和MVCC一致性读,两者协同实现ACID。

SQL 日志文件(Redo / Undo)分别做什么?

Redo 日志记录“做了什么操作”,用于崩溃恢复时重放已提交事务;Undo 日志记录“原来是什么样子”,用于回滚未提交事务、提供一致性读(MVCC)。

Redo 日志:保证持久性(Durability)

Redo 日志是物理日志,记录数据页的变更细节(比如“在某个数据页的第120字节处,把值从 0x1A 改成 0x2B”)。它写入快、顺序写、先于数据页落盘。

  • 事务提交时,只要 Redo 日志刷盘成功,就算崩溃也能恢复——InnoDB 重启后会扫描 Redo 日志,把已提交但还没写入数据文件的修改重新应用一遍
  • Redo 日志是循环复用的,由多个固定大小的文件组成(如 ib_logfile0、ib_logfile1),通过 LSN(Log Sequence number)标记位置和进度
  • 不记录 sql 语句或逻辑操作,只记录底层页级变更,所以无法直接用于闪回或审计

Undo 日志:支持回滚与多版本并发控制(MVCC)

Undo 日志是逻辑日志,记录事务修改前的数据镜像(比如“某行原来的 name 是 ‘Alice’,被更新为 ‘Bob’,那就存下 ‘Alice’”)。它保存在共享表空间或独立 Undo 表空间中。

  • 事务执行过程中,每条 INSERT/UPDATE/delete 都会生成对应的 Undo 记录;事务回滚时,就按这些记录反向还原数据
  • select 查询需要读取“过去某一时刻”的数据(快照读)时,InnoDB 会结合 Undo 链找到对应版本,实现非阻塞读
  • Undo 日志不能立刻删除——必须等到所有可能用到它的活跃事务(包括长事务、正在做快照读的事务)都结束后,才能被 purge 线程清理

两者协同工作的典型场景

假设执行一条 UPDATE 语句:

  • InnoDB 先在内存中修改数据页,并把旧值写进 Undo 日志(生成一个 Undo Log Record)
  • 再把这次修改的操作(页号、偏移、新值等)写入 Redo 日志缓冲区,随后刷盘
  • 事务提交后,Redo 日志确保修改不会丢失;若此时崩溃,恢复时靠 Redo 重做;若事务中途失败,则靠 Undo 回滚
  • 其他事务并发 SELECT 时,通过 Read View 和 Undo 链判断该行哪个版本对自己可见

常见误区提醒

red”>Redo 不是 binlog:Redo 是 InnoDB 引擎层日志,仅用于崩溃恢复;binlog 是 Server 层日志,用于主从复制和归档,格式可为 statement、row 或 mixed。

Undo 不等于回滚段(Rollback Segment)的全部:老版本 mysql 中 Undo 存在系统表空间的回滚段里;MySQL 5.6+ 支持独立 Undo 表空间,更易管理与截断。

Redo 写满会阻塞事务:如果 Redo 日志空间不足(比如 checkpoint 落后太多),新事务可能被卡住等待刷脏页,表现为“Waiting for redo log space”。

text=ZqhQzanResources