当前位置: 首页 > news >正文

MySQL-Undo Log(回滚日志)

Undo Log 是 InnoDB 存储引擎中实现事务关键组件之一。它与 Redo Log 共同协作,确保了事务的原子性(Atomicity)和一致性(Consistency),同时也是 MySQL 实现多版本并发控制(MVCC) 的基础。


一、什么是 Undo Log?

Undo Log,顾名思义,是一种用于撤销操作的日志。它记录了事务发生之前的数据状态(主要是修改前的旧版本数据)。

当执行一个 DELETEUPDATE 或 INSERT 操作时,InnoDB 不仅会生成 Redo Log 用于重做,还会生成相应的 Undo Log。如果事务需要回滚(ROLLBACK)或者系统崩溃后进行恢复,InnoDB 就可以利用 Undo Log 中的信息,将数据还原到修改前的状态。

核心思想: 在修改任何数据之前,先“留底”,把旧数据拷贝一份到 Undo Log 中。


二、Undo Log 的主要作用

  1. 实现事务回滚(原子性)
    这是 Undo Log 最直接的作用。当一个事务执行失败或用户显式执行 ROLLBACK 时,InnoDB 会读取对应事务的 Undo Log,执行相反的逆操作来撤销更改:

    • 对于 INSERT,逆操作是 DELETE

    • 对于 DELETE,逆操作是 INSERT

    • 对于 UPDATE,逆操作是用旧值再 UPDATE 回去。

  2. 实现多版本并发控制(MVCC)- 一致性读
    这是 Undo Log 在现代数据库中最重要、最高频的作用。MVCC 使得读操作(SELECT)不会阻塞写操作(UPDATE/DELETE),写操作也不会阻塞读操作

    • 当某个事务需要读取一行数据时,InnoDB 会找到该行数据的一个“可见”版本。

    • 如果该行数据的最新版本(由某个活跃事务修改)对当前读事务不可见,InnoDB 就会沿着该行记录的 DB_ROLL_PTR(回滚指针),在 Undo Log 中寻找更早的、符合当前事务隔离级别要求的旧版本数据。

    • 这些旧版本数据链(版本链)就存储在 Undo Log 中。因此,一个读请求可能会访问到很久之前的数据快照,这些快照就是通过 Undo Log 构建出来的。


三、Undo Log 的存储与结构

1. 物理存储
  • 存储位置: Undo Log 存储在表空间中。从 MySQL 5.6 开始,可以配置为使用独立的 Undo 表空间 (.ibu 文件),与系统表空间 (ibdata1) 分离,方便管理和扩展。

  • 回滚段 (Rollback Segments): InnoDB 有 128 个回滚段(Rollback Segments),其中:

    • 第 0 号、第 1 号、第 33-127 号回滚段存在于临时表空间。

    • 第 1-32 号回滚段存在于普通表空间(系统表空间或独立 Undo 表空间)。
      每个回滚段管理着多个 Undo Slot,每个 Slot 对应一个 Undo Log Segment。

  • Purge 机制: Undo Log 不会永远保留。当没有任何事务或快照读需要用到某个旧版本数据时(即该 Undo Log 不再被 MVCC 所需),这个 Undo Log 所占用的空间就可以被回收重用。这个删除过期 Undo Log 的过程由后台的 Purge 线程负责。

2. 逻辑结构 - 版本链

每一行记录(聚簇索引)在 InnoDB 中都包含两个隐藏字段:

  • DB_TRX_ID(6字节): 最近一次修改该行数据的事务 ID。

  • DB_ROLL_PTR(7字节): 回滚指针,指向该行数据的上一个旧版本在 Undo Log 中的位置。

UPDATE 操作会形成一个版本链:

  1. 事务 A (Trx-id=100) 修改了某行数据。

  2. 修改前,该行的旧数据(包括 DB_TRX_ID 和所有字段值)被拷贝到 Undo Log 中。

  3. 修改后,新行的 DB_TRX_ID 被设置为 100,DB_ROLL_PTR 指向刚刚创建的 Undo Log 记录。

  4. 当事务 B (Trx-id=200) 再次修改这行数据时,过程重复:拷贝当前状态到新的 Undo Log 记录,然后更新数据行,并将新的 DB_ROLL_PTR 指向事务 B 创建的 Undo Log 记录。

这样,通过 DB_ROLL_PTR,所有历史版本的数据就像一条链表一样被串联起来,这就是版本链

示例:
假设一行数据初始值为 Name=‘Alice’

  1. 事务 100 将其改为 Name=‘Bob’

  2. 事务 200 又将其改为 Name=‘Charlie’

这行记录及其版本链的结构如下:

当前行 (In Table)   : [Name='Charlie’, DB_TRX_ID=200, DB_ROLL_PTR --> Undo Record 200]^|
Undo Record 200      : [Name='Bob’,    DB_TRX_ID=100, DB_ROLL_PTR --> Undo Record 100]^|
Undo Record 100      : [Name='Alice’,  DB_TRX_ID=?,   DB_ROLL_PTR -> NULL]

当有一个 Read View 需要查询这行数据时,它会从最新的记录开始,顺着 DB_ROLL_PTR 依次判断哪个版本对它可见。


四、Undo Log 与 Redo Log 的区别

这是一个非常重要的概念,两者的区别和联系如下表所示:

特性Redo LogUndo Log
目的重做日志,确保事务的持久性回滚日志,确保事务的原子性一致性读(MVCC)
内容记录的是数据页的物理变化(在某个页上做了什么修改)记录的是数据修改前的逻辑状态(行的旧值)
生成时机在事务执行过程中不断写入在数据修改生成
作用时机数据库崩溃恢复时,重放已提交的事务事务回滚时和一致性读(MVCC) 时
生命周期事务提交后,对应的 Redo Log 可能很快被覆盖(循环写)事务提交后,Undo Log 可能仍被 MVCC 使用,不能立即删除
磁盘存储顺序写入(ib_logfile0/1随机写入(存在于表空间)
日志类型物理逻辑日志(物理到页,逻辑到行)逻辑日志

关键联系: Undo Log 本身的操作(写入、修改)也会产生 Redo Log。因为 Undo Log 也需要持久化,防止在写入 Undo Log 过程中发生崩溃导致数据不一致。这被称为 “Redo Log for Undo Log”


五、相关参数与最佳实践

  • innodb_undo_tablespaces: 设置独立 Undo 表空间的个数。通常建议设置为 2 或更多,便于管理和空间回收。

  • innodb_max_undo_log_size: 指定每个 Undo 表空间文件的最大大小(默认为 1GB)。超过此值,表空间会被标记为可截断。

  • innodb_undo_log_truncate: 是否启用自动截断(收缩)Undo 表空间的功能。强烈建议开启(=ON),否则 Undo 表空间会无限增长。

  • innodb_purge_threads: Purge 线程的数量。在高并发写场景下,可以适当增加此值(如设置为 4)以加快过期 Undo Log 的清理速度。

最佳实践

  1. 启用独立 Undo 表空间和自动截断,避免 ibdata1 文件无限膨胀。

  2. 对于有大事务长事务的系统,需要特别关注 Undo Log 的增长。因为一个长时间未提交的事务会阻止 Purge 线程清理它之后产生的所有 Undo Log,可能导致 Undo 表空间急剧增长。

  3. 监控 SHOW ENGINE INNODB STATUS\G 输出中的 TRANSACTIONS 部分,关注历史链表长度(History list length),它代表了未 Purge 的 Undo Log 页的数量。

总结

Undo Log 是 InnoDB 引擎的基石之一,它远不止是“回滚”那么简单。它的核心价值在于:

  1. 保障原子性:为事务回滚提供基础。

  2. 实现 MVCC:构建数据行的多版本,是实现非锁定读(快照读)、提升数据库并发性能的关键。

理解 Undo Log 的工作原理,对于深入掌握 MySQL 的事务机制、MVCC 以及进行性能调优和故障排查都至关重要。

http://www.dtcms.com/a/363885.html

相关文章:

  • 【Python3教程】Python3高级篇之多线程
  • 通用的二叉数迭代方法
  • 国内真实的交换机、路由器和分组情况
  • 容器日志加密传输在海外云服务器环境的配置标准与实施指南
  • Go结构体详解:核心概念与实战技巧
  • 计算机Python毕业设计推荐:基于Django的酒店评论文本情感分析系统【源码+文档+调试】
  • 移动端网页设计vm+rem,和px实现方式对比
  • ansible变量+管理机密
  • ansible循环+判断(with,loop,when,if,for)
  • 视觉语言模型VLM部署:基于tensorrt和tensorrt-llm的C++代码
  • 基于SpringBoot的广科大在线图书管理系统设计与实现(代码+数据库+LW)
  • Arduino Uno与4×4矩阵键盘联动完全指南
  • 百度智能云,除了AI还有啥?
  • 数据结构——树(04二叉树,二叉搜索树专项,代码练习)
  • 腾讯混元翻译模型Hunyuan-MT-7B开源:小参数量大能量,获得30项国际冠军
  • LoRA至今历程回顾(74)
  • 9.2C++——匿名对象、友元、常成员函数和常对象、运算符重载
  • 【72页PPT】企业供应链计划管理APS及运输管理OTM一体化解决方案(附下载方式)
  • 急招 MySQL / PG DBA,欢迎自荐或推荐朋友!推荐有奖!
  • GAN 网络的核心功能与深度解析
  • C语言:归并排序和计数排序
  • 从面试实战看Java技术栈深度:一个程序员的进阶之路
  • [邮件服务器core] doc www | 安装与构建
  • 前端开发中经常提到的iframe、DOM是什么?
  • 【ComfyUI】SDXL Turbo一步完成高速高效的图像生成
  • Linux - 进程切换
  • 前端sdk相关技术汇总
  • ZabbixWatch运维监控大屏
  • spring boot 整合AI教程
  • vscode无法复制terminal信息