乌龟受伤。医生准备给他包扎伤口,需要把身体反转过来。乌龟艰难的说:“我……翻不过来……”
医生问旁边的蜗牛:“你来帮他翻个身吧。”
蜗牛说:“我……也翻不过来……”
在多版本并发控制(MVCC)中,版本链和快照视图(ReadView) 是实现并发控制的两个核心概念。它们共同作用,确保事务能够在高并发环境下正确读取数据,同时实现不同的事务隔离级别。
1. 版本链
1.1 什么是版本链
版本链(Version Chain)是 MVCC 存储数据历史版本的机制。
当数据库中的一行数据发生更新或删除时,不会直接覆盖旧的数据,而是创建一个新版本,并将旧版本保留。
这些数据版本通过指针形式串联,形成一个按时间顺序排列的链条。
每个数据版本通常包含:
当前版本数据的内容。
事务标识(
xmin
和xmax
):xmin
:创建此版本的事务 ID。xmax
:删除此版本的事务 ID(如果被删除)。指向上一个版本的指针(回滚指针 Undo Pointer): 用于访问更早的历史版本。
1.2 版本链的构建
初始插入: 数据库插入一行时,只会有一个初始版本。
更新操作: 创建新版本,指向之前的版本(旧版本仍然存在)。
删除操作: 不直接删除行,而是将
xmax
标记为当前事务的事务 ID。
例如:
| 版本链示意 | xmin | xmax | 数据值 |
|---|---|---|---|
| 最新版本 | 105 | NULL | "张三" |
| 旧版本 | 102 | 105 | "李四" |
| 更旧版本 | 100 | 102 | "王五" |
1.3 版本链在 PostgreSQL 和 MySQL 中的实现
PostgreSQL 的版本链:
使用 行级别存储。
每行数据的元信息中包含
xmin
和xmax
。数据行会记录一个链式结构,每次更新或删除都会追加新版本。
旧版本的数据由 VACUUM 或 autovacuum 定期清理。
MySQL 的版本链(InnoDB 引擎):
使用回滚段(Undo Log)实现版本链。
当前行存储最新版本,历史版本保存在 Undo Log 中。
每次更新或删除时,回滚段记录旧版本信息,且最新行数据包含指向 Undo Log 的指针。
1.4 版本链的作用
支持并发读: 不同事务根据其视图需求,访问版本链中的不同版本。
支持一致性快照: 提供数据的历史状态而不互相干扰。
提高写性能: 更新不需要加锁覆盖,而是追加新版本。
2. 快照视图(ReadView)
2.1 什么是快照视图
快照视图(ReadView)是事务在开始时创建的一个逻辑数据视图,用于决定哪些数据版本对该事务可见。
它是基于版本链和事务状态的动态视图。
通过快照视图,事务可以确保在整个执行过程中读取一致的数据。
快照视图通常包含以下信息:
当前活跃事务列表: 开始时系统中尚未提交的事务 ID 列表。
最小事务 ID(
min_trx_id
): 活跃事务列表中最小的事务 ID。最大事务 ID(
max_trx_id
): 此事务启动时系统分配的最大事务 ID。当前事务 ID(
trx_id
): 执行此事务的事务 ID。
2.2 快照视图的作用
控制数据版本可见性: 确定事务能够读取哪些数据版本。
提供一致性读: 即使数据发生变化,事务也只能看到启动时的快照数据。
可见性规则:
事务只能看到符合以下规则的数据版本:
版本的
xmin
小于当前事务的trx_id
。意味着该版本是在当前事务开始之前创建的。
版本的
xmax
为 NULL,或者大于当前事务的trx_id
。如果
xmax
标记为某个事务 ID,说明该版本已被后续事务删除,不对当前事务可见。版本的创建事务 ID 不在快照视图的活跃事务列表中。
如果创建事务尚未提交,该版本对当前事务不可见。
3. 版本链与快照视图的协作
3.1 如何协作
事务启动时: 创建快照视图,记录当前系统的事务状态和活跃事务列表。
数据读取时:
遍历版本链,从最新版本开始检查。
根据快照视图的规则,判断版本是否可见。
数据修改时:
创建新版本,更新版本链。
旧版本不删除,但对后续事务的快照视图不可见。
3.2 示例
假设表中有一行数据,其版本链如下:
| 版本 | xmin | xmax | 数据值 |
|---|---|---|---|
| v3 | 105 | NULL | "张三" |
| v2 | 102 | 105 | "李四" |
| v1 | 100 | 102 | "王五" |
现有两个事务:
事务 A(
trx_id=106
)创建时的活跃事务列表:
{104, 105}
。可见数据版本:
v2
(xmin=102
,xmax=105
)。事务 B(
trx_id=107
)创建时的活跃事务列表:
{106}
。可见数据版本:
v3
(xmin=105
,xmax=NULL
)。
每个事务的快照视图决定了它读取的版本,从而实现并发读写的隔离性。
4. 优缺点分析
4.1 优点
高并发性能: 读写互不阻塞,支持更高的事务吞吐量。
数据一致性: 通过快照视图,提供事务一致性。
历史版本: 支持回滚、时间点查询等功能。
4.2 缺点
存储开销: 版本链需要存储多个版本的数据,回滚段可能消耗大量空间。
清理复杂: 需要后台任务(如 VACUUM 或 purge)定期清理无用版本。
延迟回收: 长事务可能阻止旧版本的清理。
5. 总结
版本链:存储数据的多个历史版本,通过指针链接形成数据版本的时间序列。
快照视图:事务开始时创建的逻辑视图,用于判断数据版本的可见性。
协同工作:版本链提供历史数据支持,快照视图根据事务逻辑决定可见性。
这种机制确保了 MVCC 的核心特性:读写分离、一致性读 和 高并发处理能力。




