华为云AgentArts实战:金融信贷智能体工作流编排与调优
2026/10/6 20:13:39
在 MySQL InnoDB 的 MVCC 机制中,版本链是一行数据的所有历史版本通过回滚指针串联起来的单向链表,它是实现快照读的核心数据结构。
版本链的每一个节点,都是一行数据的一个历史版本,而串联这些节点的关键,就是 InnoDB 为每行数据隐式添加的两个字段:
DB_TRX_ID标记创建这个版本的事务 ID,相当于给这个版本贴了一个 “身份标签”。DB_ROLL_PTR(回滚指针)这是版本链的 “链条”,它指向当前版本的上一个历史版本(这个历史版本存储在undo log中)。除此之外,每行数据的最新版本会直接存储在数据页中,而历史版本则全部保存在undo log里。
我们用一个具体的例子,看一行数据的版本链是如何随着事务操作逐步变长的。假设表user有一行初始数据:id=1, name="张三",此时它的隐藏字段状态:
DB_TRX_ID = 0(表示这是初始化版本,无事务修改)DB_ROLL_PTR = null(无历史版本,链表头)BEGIN; UPDATE user SET name = "李四" WHERE id = 1; COMMIT;InnoDB 的处理逻辑:
name=张三, DB_TRX_ID=0, DB_ROLL_PTR=null)拷贝到undo log中;name=李四,更新隐藏字段:DB_TRX_ID = 101(标记是事务 101 修改的)DB_ROLL_PTR = 指向 undo log 中的原始版本数据页当前版本(101: 李四) → undo log 历史版本(0: 张三)BEGIN; UPDATE user SET name = "王五" WHERE id = 1; COMMIT;InnoDB 的处理逻辑:
name=李四, DB_TRX_ID=101, DB_ROLL_PTR=指向旧版本)拷贝到undo log;name=王五,更新隐藏字段:DB_TRX_ID = 102DB_ROLL_PTR = 指向 undo log 中的 101 版本数据页当前版本(102: 王五) → undo log 版本1(101: 李四) → undo log 版本2(0: 张三)UPDATE/DELETE操作,都会生成一个新的历史版本,并追加到版本链尾部;INSERT操作不会生成历史版本(因为插入前该行不存在),所以不会影响版本链;版本链的唯一作用,就是为快照读提供历史版本数据,配合Read View实现 “读不阻塞写”。
具体流程是:
SELECT)时,会生成一个Read View(版本可见性规则);Read View判断这个版本是否可见:DB_ROLL_PTR遍历版本链,去undo log中找下一个历史版本;Read View规则的可见版本,返回该版本数据。版本链不会无限变长,否则undo log会越来越大,占用大量磁盘空间。InnoDB 的purge 线程会定期清理版本链中不再需要的历史版本—— 判断标准是:
没有任何活跃事务的
Read View会用到这个历史版本。
比如,所有事务的快照读都不需要访问undo log中的 0 版本了,purge 线程就会把这个版本从undo log中删除,版本链也会相应缩短。