MySQ回滚日志Undo Log实践记录

 更新时间:2025年09月03日 11:34:35   作者:M_Reus_11  
Undo Log是一种用于撤销操作的日志,它记录了事务发生之前的数据状态(主要是修改前的旧版本数据),本文给大家介绍MySQ回滚日志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 的主要作用

  • 实现事务回滚(原子性)
  • 这是 Undo Log 最直接的作用。当一个事务执行失败或用户显式执行 ROLLBACK 时,InnoDB 会读取对应事务的 Undo Log,执行相反的逆操作来撤销更改:
    • 对于 INSERT,逆操作是 DELETE
    • 对于 DELETE,逆操作是 INSERT
    • 对于 UPDATE,逆操作是用旧值再 UPDATE 回去。
  • 实现多版本并发控制(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 操作会形成一个版本链:

  • 事务 A (Trx-id=100) 修改了某行数据。
  • 修改前,该行的旧数据(包括 DB_TRX_ID 和所有字段值)被拷贝到 Undo Log 中。
  • 修改后,新行的 DB_TRX_ID 被设置为 100,DB_ROLL_PTR 指向刚刚创建的 Undo Log 记录。
  • 当事务 B (Trx-id=200) 再次修改这行数据时,过程重复:拷贝当前状态到新的 Undo Log 记录,然后更新数据行,并将新的 DB_ROLL_PTR 指向事务 B 创建的 Undo Log 记录。

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

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

  • 事务 100 将其改为 Name=‘Bob’
  • 事务 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 的清理速度。

最佳实践

  • 启用独立 Undo 表空间和自动截断,避免 ibdata1 文件无限膨胀。
  • 对于有大事务长事务的系统,需要特别关注 Undo Log 的增长。因为一个长时间未提交的事务会阻止 Purge 线程清理它之后产生的所有 Undo Log,可能导致 Undo 表空间急剧增长。
  • 监控 SHOW ENGINE INNODB STATUS\G 输出中的 TRANSACTIONS 部分,关注历史链表长度(History list length),它代表了未 Purge 的 Undo Log 页的数量。

总结

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

  • 保障原子性:为事务回滚提供基础。
  • 实现 MVCC:构建数据行的多版本,是实现非锁定读(快照读)、提升数据库并发性能的关键。

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

到此这篇关于MySQ回滚日志Undo Log实践记录的文章就介绍到这了,更多相关MySQ回滚Undo Log内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • MySQL8.0 如何快速加列

    MySQL8.0 如何快速加列

    这篇文章主要介绍了MySQL8.0 如何快速加列,帮助大家更好的理解和使用MySQL数据库,感兴趣的朋友可以了解下
    2020-09-09
  • CentOS 7中源码安装MySQL 5.7.6+详细教程

    CentOS 7中源码安装MySQL 5.7.6+详细教程

    最近在CentOS 7中源码安装MySQL 5.7.6+,发现MySQL5.7.6+以后的安装方式真的与以前版本的MySQL安装方式大大的不同呀。不自己安装一把,你都不知道不同之处在哪,下面这篇文章是通过自己的安装过程总结的一篇安装教程,有需要的朋友们可以参考借鉴,下面来一起看看吧。
    2016-12-12
  • mysql锁表确认及解除锁表的实现示例

    mysql锁表确认及解除锁表的实现示例

    使用MySQL数据库时,我们可能会遇到数据库表被锁定的情况,本文主要介绍了mysql锁表确认及解除锁表的实现示例, 具有一定的参考价值,感兴趣的可以了解一下
    2024-06-06
  • MYSQL必知必会读书笔记第八章之使用通配符进行过滤

    MYSQL必知必会读书笔记第八章之使用通配符进行过滤

    这篇文章主要介绍了MYSQL必知必会读书笔记第八章之使用通配符进行过滤的相关资料,需要的朋友可以参考下
    2016-05-05
  • mysql如何分别按年/月/日/周分组统计数据详解

    mysql如何分别按年/月/日/周分组统计数据详解

    我们在用Mysql抽取数据时候,经常需要按照天、周、月等不同的粒度对数据进行分组统计,下面这篇文章主要给大家介绍了关于mysql如何分别按年/月/日/周分组统计数据的相关资料,需要的朋友可以参考下
    2022-12-12
  • MySql5.7.21安装要点记录笔记

    MySql5.7.21安装要点记录笔记

    这篇文章主要介绍了mysql5.7.21安装要点记录笔记,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2018-02-02
  • MySQL数据库开发的36条原则(小结)

    MySQL数据库开发的36条原则(小结)

    这篇文章主要介绍了MySQL数据库开发的36条原则(小结),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-09-09
  • mysql创建表设置表主键id从1开始自增的解决方案

    mysql创建表设置表主键id从1开始自增的解决方案

    在MySQL中用很多类型的自增ID,每个自增ID都设置了初始值,一般情况下初始值都是从0开始,然后按照一定的步长增加(一般是自增 1),下面这篇文章主要给大家介绍了关于mysql创建表设置表主键id从1开始自增的解决方案,需要的朋友可以参考下
    2023-04-04
  • 基于Php mysql存储过程的详解

    基于Php mysql存储过程的详解

    本篇文章是对Php中的mysql存储过程进行了详细的分析介绍,需要的朋友参考下
    2013-06-06
  • mysql分表和分区的区别浅析

    mysql分表和分区的区别浅析

    这篇文章主要介绍了mysql分表和分区的区别浅析,并对它们之间的相同做了分析,需要的朋友可以参考下
    2014-07-07

最新评论