MySQL 如何插入记录的 Undo 日志?

Undo 模块的第二篇,聊聊插入记录产生的 Undo 日志格式。

作者:操盛春,爱可生技术专家,公众号『一树一溪』作者,专注于研究 MySQL 和 OceanBase 源码。 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。 本文基于 MySQL 8.0.32 源码,存储引擎为 InnoDB。

1. 准备工作

创建测试表:

CREATE TABLE `t1` (
  `id` int unsigned NOT NULL AUTO_INCREMENT,
  `i1` int DEFAULT '0',
  PRIMARY KEY (`id`) USING BTREE,
  KEY `idx_i1` (`i1`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3;

示例 SQL:

INSERT INTO `t1` (`id`, `i1`)
VALUES (50, 501);

2. Insert Undo 日志格式

插入一条记录到表中,首先会插入记录到主键索引,然后遍历二级索引,把记录插入到各个二级索引中。

插入记录到主键索引之前,会生成 Undo 日志,并写入 Undo 页。插入记录到二级索引,不会生成 Undo 日志。插入记录的 Undo 日志格式比较简单,如下图所示。

各属性详细说明如下:

  • next_record_offset,占用 2 字节,表示下一条 Undo 日志在 Undo 页中的偏移量。
  • undo_type,占用 1 字节,表示这条 Undo 日志的类型。插入记录产生的 Undo 日志,类型为 TRX_UNDO_INSERT_REC
  • undo_no,64 位整数,压缩之后占用 1 ~ 11 字节,表示这条 Undo 日志的编号。
  • table_id,64 位整数,压缩之后占用 1 ~ 11 字节,这个属性值是表 ID,表示事务插入记录到哪个表产生的这条 Undo 日志。
  • len,32 位整数,压缩之后占用 1 ~ 5 字节,表示主键字段值的长度。
  • value,占用多少字节的存储空间,取决于主键字段的数据类型和具体值,这个属性中存储的就是主键字段值,存储时不会压缩。
  • current_record_offset,这条 Undo 日志在 Undo 页中的偏移量。

如果主键是由多个字段组成的联合主键,插入记录产生的 Undo 日志中,会按照联合主键定义的字段顺序写入所有主键字段的长度和值:len_1、value_1、len_2、value_2、...、len_N、value_N。

3. Insert Undo 日志内容

示例 SQL 插入记录到 t1 表中产生的 Undo 日志,如下图所示。

各属性值详细说明如下:

  • 285,下一条 Undo 日志在 Undo 页中的偏移量。这个值不会压缩,固定占用 2 字节。
  • 11,表示这条 Undo 日志是插入记录产生的,代码里定义为 TRX_UNDO_INSERT_REC。这个值不会压缩,固定占用 1 字节。
  • 0,这条 Undo 日志的编号。压缩之后占用 1 字节。
    这个值来源于事务对象的 undo_no 属性。事务产生的第一条 Undo 日志编号为 0,第二条 Undo 日志编号为 1,依此类推。
  • 1412,这是 t1 表的 ID。压缩之后占用 2 字节。
  • 4,主键字段值的长度。压缩之后占用 1 字节。
  • 50,主键字段值。主键字段类型为 int unsigned,占用 4 字节。
  • 272,这条 Undo 日志在 Undo 页中的偏移量。这个值不会压缩,固定占用 2 字节。

4. Insert Undo 日志地址

InnoDB 存储引擎的表中,每条记录都有个隐藏字段 DB_ROLL_PTR,字段长度固定为 7 字节。通过这个字段值可以找到 Undo 日志(也是 MVCC 中记录的历史版本)。

从整体上来看,我们可以认为它是 Undo 日志的地址。但是,这个字段值实际上由 4 部分组成,如下图所示。

各属性详细说明如下:

  • is_insert,表示这条 Undo 日志是否是插入记录产生的。
  • undo_space_id,这条 Undo 日志所属 Undo 表空间的 ID。
    InnoDB 最多支持 127 个 Undo 表空间,ID 范围是 0 ~ 127。7 bit 可以表示的最大数字正好是 127。
  • page_no,这条 Undo 日志所属 Undo 页的页号。
  • offset,这条 Undo 日志在 Undo 页中的偏移量。

DB_ROLL_PTR 的计算公式如下:

is_insert << 55 | undo_space_id << 48 | page_no << 16 | offset

以示例 SQL 为例,插入记录时产生 Undo 日志得到的各属性值如下:

  • is_insert = true, 转换成整数就是 1。
  • undo_space_id = 2。
  • page_no = 573。
  • offset = 272。

用 Shell 按照以上公式计算得到 DB_ROLL_PTR,如下:

# 输出结果为 36591747009937680
echo $((1 << 55 | 2 << 48 | 573 << 16 | 272))

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

SQLE 是一款全方位的 SQL 质量管理平台,覆盖开发至生产环境的 SQL 审核和管理。支持主流的开源、商业、国产数据库,为开发和运维提供流程自动化能力,提升上线效率,提高数据质量。

✨ Github:https://github.com/actiontech/sqle

📚 文档:https://actiontech.github.io/sqle-docs/

💻 官网:https://opensource.actionsky.com/sqle/

👥 微信群:请添加小助手加入 ActionOpenSource

🔗 商业支持:https://www.actionsky.com/sqle

<think>嗯,用户想了解MySQL的三大日志类型及其作用。我需要先回忆一下相关知识。根据之前提供的参考内容,三大日志应该是Redo Log、Undo Log和Bin Log。 首先,Redo Log,也就是重做日志。我记得它的主要作用是崩溃恢复,确保事务的持久性。当数据库崩溃时,通过重做日志可以将未写入数据文件的操作重新执行,保证数据不丢失。参考里提到它记录物理修改,比如页的修改,这样恢复起来更快。另外,它还是循环写的,固定大小,这样性能比较好。 接下来是Undo Log,回滚日志。它的作用是帮助事务回滚和实现MVCC(多版本并发控制)。比如,当一个事务需要回滚时,Undo Log会记录之前的版本,可以恢复到修改前的状态。同时,在读取数据时,其他事务可能还在进行,Undo Log提供一致性读,确保事务隔离。参考里提到它记录逻辑日志,比如反向的SQL语句,这样回滚的时候更灵活。 然后是Bin Log,二进制日志。这个日志主要用来做数据恢复、主从复制和审计。它记录的是逻辑操作,比如执行的SQL语句或者数据变更前后的内容。和Redo Log不同,Bin Log是追加写入的,不会覆盖旧日志。主从复制的时候,从库就是通过Bin Log来同步数据的。参考里还提到开启Bin Log需要在配置文件中设置log_bin参数,并指定路径。 需要确认这三个日志的区别和各自的功能,不能混淆。比如Redo Log是InnoDB引擎特有的,而Bin Log是MySQL服务器层实现的。Undo Log也是InnoDB层的,用于事务回滚和MVCC。另外,Redo Log是物理日志记录的是数据页的修改,而Bin Log是逻辑日志记录的是操作语句。 用户可能还会想知道这些日志如何配置,或者它们对性能的影响。参考里提到开启日志会影响性能,比如查询频繁时记录日志会花时间,占用磁盘空间。但这些都是必要的权衡,保证数据的安全和一致性。 总结一下,三大日志分别是Redo Log(崩溃恢复)、Undo Log(事务回滚和MVCC)、Bin Log(主从复制和数据恢复)。各自的作用需要明确区分,物理和逻辑日志的不同,以及它们在事务处理和数据库高可用性中的角色。</think>### MySQL三大日志类型及功能介绍 MySQL的三大核心日志系统是$Redo\ Log$(重做日志)、$Undo\ Log$(回滚日志)和$Bin\ Log$(二进制日志)。它们分别承担不同的功能,共同保障数据库的**可靠性**、**事务特性**和**数据恢复能力**。 --- #### 1. Redo Log(重做日志) - **功能**: 记录事务对数据页的**物理修改**,用于**崩溃恢复**和**提升事务提交效率**。 - **崩溃恢复**:当MySQL异常重启时,通过重做日志将未持久化到磁盘的修改重新应用,确保事务的持久性(ACID中的Durability)[^1][^3]。 - **性能优化**:事务提交时只需写入重做日志(顺序写),而非直接刷盘(随机写),减少I/O开销。 - **特点**: - 采用循环写入模式,文件大小固定。 - 属于InnoDB引擎层实现,仅记录物理修改(如“页编号X的偏移量Y写入数据Z”)[^3]。 --- #### 2. Undo Log(回滚日志) - **功能**: 记录事务的**逻辑操作逆向信息**,用于实现**事务回滚**和**多版本并发控制(MVCC)**。 - **事务回滚**:若事务未提交或需要回滚,通过Undo Log逆向恢复数据到原始状态,保障原子性(ACID中的Atomicity)[^1][^3]。 - **MVCC支持**:为读操作提供一致性视图,避免读写冲突(如事务隔离级别`REPEATABLE READ`的实现)。 - **特点**: - 逻辑日志,例如记录“INSERT操作的逆向操作为DELETE”。 - 存储在回滚段(Rollback Segment)中,由InnoDB管理。 --- #### 3. Bin Log(二进制日志) - **功能**: 记录数据库的**逻辑操作**(如SQL语句或数据变更前后的状态),用于**主从复制**、**数据恢复**和**审计**。 - **主从复制**:从库通过重放Bin Log实现数据同步[^4]。 - **数据恢复**:结合全量备份和Bin Log,可将数据库恢复到任意时间点[^2]。 - **特点**: - 属于MySQL Server层实现,所有存储引擎均可使用。 - 支持三种格式:`STATEMENT`(记录SQL语句)、`ROW`(记录行变更)、`MIXED`(混合模式)。 - 需通过配置`log_bin`参数启用,并指定日志路径。 --- ### 性能与配置注意事项 - **性能影响**:开启日志会占用额外I/O和磁盘空间,例如频繁查询场景下,Bin Log和慢查询日志可能降低性能。 - **典型配置**: ```ini [mysqld] log_bin = /var/log/mysql/mysql-bin # 启用Bin Log server_id = 1 # 主从复制需唯一ID ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值