暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

数据库mvcc中版本链与ReadView详解

解压泡泡糖 2024-11-27
189

乌龟受伤。医生准备给他包扎伤口,需要把身体反转过来。乌龟艰难的说:“我……翻不过来……”

医生问旁边的蜗牛:“你来帮他翻个身吧。”

蜗牛说:“我……也翻不过来……”


在多版本并发控制(MVCC)中,版本链快照视图(ReadView) 是实现并发控制的两个核心概念。它们共同作用,确保事务能够在高并发环境下正确读取数据,同时实现不同的事务隔离级别。


1. 版本链

1.1 什么是版本链

版本链(Version Chain)是 MVCC 存储数据历史版本的机制。

  • 当数据库中的一行数据发生更新或删除时,不会直接覆盖旧的数据,而是创建一个新版本,并将旧版本保留。

  • 这些数据版本通过指针形式串联,形成一个按时间顺序排列的链条。

每个数据版本通常包含:

  • 当前版本数据的内容

  • 事务标识(xmin
    xmax
    ):

    • xmin
      :创建此版本的事务 ID。

    • xmax
      :删除此版本的事务 ID(如果被删除)。

  • 指向上一个版本的指针(回滚指针 Undo Pointer): 用于访问更早的历史版本。

1.2 版本链的构建

  • 初始插入: 数据库插入一行时,只会有一个初始版本。

  • 更新操作: 创建新版本,指向之前的版本(旧版本仍然存在)。

  • 删除操作: 不直接删除行,而是将 xmax
    标记为当前事务的事务 ID。

例如:

版本链示意xmin
xmax
数据值
最新版本105NULL"张三"
旧版本102105"李四"
更旧版本100102"王五"

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 快照视图的作用

  • 控制数据版本可见性: 确定事务能够读取哪些数据版本。

  • 提供一致性读: 即使数据发生变化,事务也只能看到启动时的快照数据。

可见性规则:

事务只能看到符合以下规则的数据版本:

  1. 版本的 xmin
    小于当前事务的 trx_id

    • 意味着该版本是在当前事务开始之前创建的。

  2. 版本的 xmax
    为 NULL,或者大于当前事务的 trx_id

    • 如果 xmax
      标记为某个事务 ID,说明该版本已被后续事务删除,不对当前事务可见。

  3. 版本的创建事务 ID 不在快照视图的活跃事务列表中。

    • 如果创建事务尚未提交,该版本对当前事务不可见。


3. 版本链与快照视图的协作

3.1 如何协作

  • 事务启动时: 创建快照视图,记录当前系统的事务状态和活跃事务列表。

  • 数据读取时:

    • 遍历版本链,从最新版本开始检查。

    • 根据快照视图的规则,判断版本是否可见。

  • 数据修改时:

    • 创建新版本,更新版本链。

    • 旧版本不删除,但对后续事务的快照视图不可见。

3.2 示例

假设表中有一行数据,其版本链如下:

版本xmin
xmax
数据值
v3105NULL"张三"
v2102105"李四"
v1100102"王五"

现有两个事务:

  • 事务 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 的核心特性:读写分离一致性读高并发处理能力


文章转载自解压泡泡糖,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论