Techoc`s

Techoc`s

INSERT 、 DELETE 、 UPDATE 这些会对数据做改动的语句都会产生什么类型的 undo日志

2026-03-02

INSERT 、 DELETE 、 UPDATE 这些会对数据做改动的语句都会产生什么类型的 undo日志

InnoDB 存储引擎中,INSERTDELETEUPDATE 这些数据改动语句在执行时,都会生成相应的 undo 日志(撤销日志)。undo 日志主要用于两个目的:

  1. 事务回滚:当事务执行 ROLLBACK 时,需要根据 undo 日志将数据恢复到修改前的状态。
  2. 多版本并发控制(MVCC):为一致性读(快照读)提供历史版本数据。

不同类型的操作会产生不同类型的 undo 日志,下面详细说明。


1. INSERT 操作

  • 产生的 undo 日志类型TRX_UNDO_INSERT_REC
  • 特点
    • 插入一条新记录时,需要记录这条记录的主键信息(如果是聚簇索引)以及必要的索引列信息,以便在回滚时能够准确地删除这条记录。
    • 由于插入操作没有“旧版本”,因此这类 undo 日志不参与 MVCC 的版本链(即它的 roll_pointerNULL)。
    • 结构上,它只记录了主键各列的长度和值,以及表 ID 等信息。
  • 回滚时的作用:执行 ROLLBACK 时,根据记录的主键找到这条记录并删除。
  • 事务提交后的处理TRX_UNDO_INSERT_REC 只在事务回滚时有用,事务提交后即可被清理(或放入可重用缓存)。因为它不用于 MVCC,所以可以被快速释放。

2. DELETE 操作

  • 产生的 undo 日志类型TRX_UNDO_DEL_MARK_REC
  • 特点
    • InnoDB 中删除操作并非立即物理移除记录,而是先对记录做 delete mark(标记删除),将记录头中的 delete_flag 置为 1,同时更新记录的 trx_idroll_pointer
    • 在标记删除之前,需要将记录的旧版本信息(包括被删除前的完整记录内容以及所有索引列的值)写入 undo 日志,以便回滚时能够恢复这条记录。
    • 这类 undo 日志会参与 MVCC 版本链,因为被标记删除的记录仍然对其他事务可见(取决于隔离级别和 ReadView)。
  • 结构
    • 包含被删除记录的完整旧值(所有列),以及主键信息。
    • 还包含旧版本的 trx_idroll_pointer,以便链接到更早的版本。
  • 回滚时的作用:执行 ROLLBACK 时,根据 undo 日志中的内容重新插入这条记录(清除 delete mark 并恢复所有列的值)。
  • 事务提交后的处理TRX_UNDO_DEL_MARK_REC 不能立即清理,因为它可能仍被其他事务的 MVCC 需要。只有等到系统中所有活跃事务的 ReadView 都不再需要这个旧版本时,才会由 purge 线程真正物理删除记录并释放 undo 日志。

3. UPDATE 操作

UPDATE 的情况比较复杂,根据是否更新主键以及被更新的列在修改前后占用的存储空间是否变化,会产生不同类型的 undo 日志。

3.1 不更新主键的情况

  • 如果更新不涉及主键,且被更新的列存储空间未发生变化(例如将 VARCHAR(10) 的 'abc' 改为 'def',长度相同),可以进行 就地更新(in-place update)。此时会生成一条 TRX_UNDO_UPD_EXIST_REC 类型的 undo 日志。
    • 该日志记录了被修改列的旧值,以及必要的索引列信息(如果修改了索引列)。
    • 回滚时,根据这些旧值将记录还原。
  • 如果更新不涉及主键,但被更新的列存储空间发生变化(例如将短字符串改为长字符串,无法就地更新),则需要先删除旧记录,再插入新记录。这个过程会产生两条 undo 日志:
    • 一条 TRX_UNDO_DEL_MARK_REC 用于标记删除旧记录(记录旧值)。
    • 一条 TRX_UNDO_INSERT_REC 用于新插入的记录(记录新记录的主键)。
    • 注意:这里的“删除”仍然是标记删除,旧记录保留在页面中,新记录插入后,旧记录通过版本链指向新记录?实际上,这种情况 InnoDB 的处理是:先在原记录位置做 delete mark,然后插入一条新记录(可能在不同位置)。旧记录的 roll_pointer 指向其对应的 undo 日志(包含旧值),新记录的 roll_pointer 指向旧记录的 undo 日志?实际实现中,新记录会通过 roll_pointer 指向旧记录的 undo 日志,从而形成版本链。但产生的 undo 日志类型仍然是 TRX_UNDO_DEL_MARK_RECTRX_UNDO_INSERT_REC

3.2 更新主键的情况

  • 如果更新了主键列,InnoDB 的处理方式是:
    1. 将原记录做 delete mark(标记删除),产生一条 TRX_UNDO_DEL_MARK_REC 类型的 undo 日志。
    2. 插入一条新记录(因为主键改变,记录在聚簇索引中的位置会变化),产生一条 TRX_UNDO_INSERT_REC 类型的 undo 日志。
  • 这两条 undo 日志的作用:
    • TRX_UNDO_DEL_MARK_REC 用于回滚时恢复旧记录。
    • TRX_UNDO_INSERT_REC 用于回滚时删除新插入的记录。
  • 版本链的处理:旧记录通过 roll_pointer 指向其 TRX_UNDO_DEL_MARK_REC 日志,新记录通过 roll_pointer 指向旧记录的 undo 日志?实际上,由于主键改变,新记录和旧记录在 B+ 树中位于不同位置,它们之间并没有直接的 roll_pointer 链接,但旧记录的版本链仍然保留,新记录开启新的版本链。不过,对于 MVCC 来说,新记录和旧记录是两条不同的记录,各自有独立的版本链。

3.3 UPDATE 产生的 undo 日志总结

场景产生的 undo 日志类型
不更新主键,且可原地更新TRX_UNDO_UPD_EXIST_REC(一条)
不更新主键,但需删除+插入TRX_UNDO_DEL_MARK_REC(旧记录) + TRX_UNDO_INSERT_REC(新记录)
更新主键TRX_UNDO_DEL_MARK_REC(旧记录) + TRX_UNDO_INSERT_REC(新记录)

无论哪种 UPDATE,产生的 TRX_UNDO_UPD_EXIST_RECTRX_UNDO_DEL_MARK_REC 都属于 update undo 大类,它们都参与 MVCC 版本链,事务提交后不能立即清理,需要等待 purge。而 TRX_UNDO_INSERT_REC 属于 insert undo 大类,事务提交后可立即重用或释放。


4. 各类 undo 日志的归属大类

InnoDB 将 undo 日志分为两个大类,分别存储在不同的 undo 段中:

  • insert undo:仅包含 TRX_UNDO_INSERT_REC 类型的日志。这类日志只用于事务回滚,不参与 MVCC,事务提交后可快速处理。
  • update undo:包含 TRX_UNDO_DEL_MARK_RECTRX_UNDO_UPD_EXIST_REC 等类型的日志。它们用于 MVCC 和事务回滚,需要保留到不再被任何活跃事务需要为止。

5. 示例说明

假设有如下表:

CREATE TABLE t (id INT PRIMARY KEY, name VARCHAR(10)) Engine=InnoDB;
INSERT INTO t VALUES (1, 'Alice');
  • INSERT:插入 (1, 'Alice') 产生一条 TRX_UNDO_INSERT_REC,记录主键值 1
  • DELETE:删除 id=1 的记录,产生一条 TRX_UNDO_DEL_MARK_REC,记录整行旧值 (1, 'Alice')
  • UPDATE:将 name'Alice' 改为 'Bob'(长度不变),产生一条 TRX_UNDO_UPD_EXIST_REC,记录旧值 'Alice'
  • UPDATE 更新主键:将 id1 改为 2,产生两条日志:
    • 对旧记录 (1, 'Alice') 标记删除,生成 TRX_UNDO_DEL_MARK_REC
    • 插入新记录 (2, 'Alice'),生成 TRX_UNDO_INSERT_REC

6. 总结

操作产生的 undo 日志类型所属大类用途事务提交后处理
INSERTTRX_UNDO_INSERT_RECinsert undo回滚时根据主键删除记录可立即重用或释放
DELETETRX_UNDO_DEL_MARK_RECupdate undo回滚时恢复记录,为 MVCC 提供旧版本保留至不再被需要,由 purge 清理
UPDATETRX_UNDO_UPD_EXIST_RECupdate undo回滚时恢复被修改列的旧值,为 MVCC 提供旧版本保留至不再被需要,由 purge 清理
TRX_UNDO_DEL_MARK_REC + TRX_UNDO_INSERT_REC混合回滚时删除新记录、恢复旧记录分别按各自规则处理

理解不同操作产生的 undo 日志类型,有助于深入掌握 InnoDB 的事务回滚和 MVCC 机制,也对分析 undo 表空间的使用情况、优化 purge 线程性能有指导意义。