当前位置: 首页 > article >正文

02_MVCC-版本链管理

MVCC-版本链管理

文章目录

    • MVCC-版本链管理
        • 简介
        • 基本概念
        • 版本链的形成与管理
          • 数据插入操作
          • 数据更新操作
          • 数据删除操作
        • 一致性视图(Read View)
        • 快照读与当前读
          • 快照读(Snapshot Read)
          • 当前读(Current Read)
        • 优缺点
          • 优点
          • 缺点
        • 版本链的清理
        • 总结
        • 延伸

简介

MySQL 的 MVCC(Multiversion Concurrency Control,多版本并发控制)机制通过版本链管理来实现数据的多版本存储,从而支持高并发的读写操作。


基本概念

InnoDB 存储引擎在实现 MVCC 时,会为每一行数据维护一个版本链,这些版本链用于记录数据的多个版本。每个版本包含以下隐藏列:

  1. DB_TRX_ID(事务ID):记录创建或最后一次修改该版本的事务ID。
  2. DB_ROLL_PTR(回滚指针):指向该行数据的上一个版本的指针。
  3. DB_ROW_ID:隐式的自增ID,用于唯一标识行记录。有主键的时候会使用主键,没有主键的时候会自动生成一个行 Id 作为聚簇索引。

这些隐藏列在实际的数据表结构中不可见,但它们是实现 MVCC 的关键。


版本链的形成与管理
数据插入操作

当插入一行新数据时,InnoDB 会为该行分配一个新的事务ID,并将 DB_TRX_ID 设置为当前事务ID。同时,因为这是一条新记录,没有上一个版本,所以 DB_ROLL_PTR 为空。

INSERT INTO example (id, value) VALUES (1, 'A');

在此操作中,假设事务ID 为 trx_id = 100,新记录会包含如下信息:

  • id = 1
  • value = 'A'
  • DB_TRX_ID = 100
  • DB_ROLL_PTR = NULL
数据更新操作

当更新一行数据时,InnoDB 不会直接覆盖原数据,而是创建一个新的版本。新版本会记录当前事务ID,并通过 DB_ROLL_PTR 指向旧版本。

UPDATE example SET value = 'B' WHERE id = 1;

假设事务ID 为 trx_id = 101,更新后的新记录会包含如下信息:

  • id = 1
  • value = 'B'
  • DB_TRX_ID = 101
  • DB_ROLL_PTR 指向旧版本

旧版本数据保存在回滚日志(Undo Log)中,包含以下信息:

  • id = 1
  • value = 'A'
  • DB_TRX_ID = 100
  • DB_ROLL_PTR = NULL

通过这种方式,InnoDB 形成了一个版本链,新版本指向旧版本,实现数据的多版本存储。

数据删除操作

当删除一行数据时,InnoDB 同样不会直接物理删除该行,而是创建一个标记为“已删除”的新版本,并指向旧版本。

DELETE FROM example WHERE id = 1;

假设事务ID 为 trx_id = 102,删除后的新记录会包含如下信息:

  • id = 1
  • value = NULL(表示该行已被删除)
  • DB_TRX_ID = 102
  • DB_ROLL_PTR 指向旧版本

一致性视图(Read View)

当一个事务开始时,InnoDB 会创建一个一致性视图(Read View),该视图记录当前系统中活跃事务的 ID,用于决定哪些版本对当前事务可见。具体来说:

  1. m_ids:当前系统中所有活跃事务的 ID 列表。
  2. min_trx_idm_ids 中最小的事务ID。
  3. max_trx_id:当前系统中将要分配的下一个事务ID。
  4. creator_trx_id:创建这个 Read View 的事务ID。

通过一致性视图,InnoDB 能够决定某个数据版本是否对当前事务可见:

  • 如果数据版本(要读取的数据行)的 DB_TRX_ID 小于 min_trx_id(当前事务开始时创建的一致性视图中的 min_trx_id),表示这个版本(要读取的数据行)在当前事务开始之前就已经提交了,所以这个版本(要读取的数据行)对当前事务是可见的。
  • 如果数据版本的 DB_TRX_ID 大于或等于 max_trx_id,表示这个版本在当前事务开始之后才创建,所以是不可见的。
  • 如果数据版本的 DB_TRX_IDmin_trx_idmax_trx_id 之间,则需要进一步检查该 DB_TRX_ID 是否在 m_ids 中:
    • 如果在,表示这个版本是由一个尚未提交的事务创建的,所以是不可见的。
    • 如果不在,则表示这个版本是由一个已经提交的事务创建的,所以是可见的。

如果当前版本对事务不可见,InnoDB 会沿着版本链(通过 roll_pointer 指针)查找上一个版本,重复上述判断过程,直到找到一个对当前事务可见的版本。


快照读与当前读
快照读(Snapshot Read)

快照读是读取一致性视图中的数据版本,而不加锁。这种读操作通常用于 SELECT 查询。

-- 事务1:启动事务
START TRANSACTION;
-- 快照读,读取一致性视图中的数据
SELECT * FROM example WHERE id = 1;

在快照读中,InnoDB 会根据一致性视图和版本链,选择一个对当前事务可见的数据版本返回。

当前读(Current Read)

当前读是读取最新的数据版本并加锁,确保数据的一致性。这种读操作用于需要更新或锁定数据的查询,如 SELECT ... FOR UPDATESELECT ... LOCK IN SHARE MODE

-- 事务1:启动事务
START TRANSACTION;
-- 当前读,加排他锁
SELECT * FROM example WHERE id = 1 FOR UPDATE;

在当前读中,InnoDB 会读取最新的数据版本,并根据操作类型加上合适的锁(如排他锁或共享锁)。


优缺点
优点
  1. 高并发性能:通过多版本数据存储,读操作无需加锁,提高了系统的并发性能。
  2. 数据一致性:通过一致性视图和版本链,确保在事务隔离级别下的数据一致性。
  3. 事务隔离:支持事务的隔离级别,如可重复读和读已提交,避免了脏读、不可重复读和幻读问题。
缺点
  1. 存储开销:需要额外存储多版本数据和回滚日志,增加了存储需求。
  2. 数据清理:需要定期清理无用的旧版本数据,避免回滚日志无限增长,增加了系统维护的复杂性。

通过详细理解版本链管理,可以更好地掌握 MySQL 的 MVCC 机制,提高数据库系统的性能和数据一致性。


版本链的清理

随着时间的推移,旧版本的数据可能不再被任何事务需要,因此 InnoDB 会定期清理这些不再需要的版本,这个过程被称为 purge。Purge 操作会检查 undo log 记录,并在确定没有事务需要访问这些旧版本时将其删除,释放空间供将来使用。


总结

MySQL 中的 MVCC 通过在每行记录中维护额外的系统字段来构建版本链,这使得不同事务可以看到数据的不同版本。版本链的管理涉及到版本的创建、读取版本的可见性判断,以及不再需要的版本的清理。这种机制允许事务并发执行,同时保持一致性和隔离性,是 InnoDB 高效性能的关键所在。


延伸
  1. 一致性视图的实现原理(快照如何存储?存储在哪?多个快照存在时如何选取版本等)

http://www.kler.cn/news/360709.html

相关文章:

  • json路径 [‘a‘].b.c[0].d[‘1‘].f,具体代表什么意思
  • 无人机之标校技术篇
  • Java项目-基于springboot框架的网上图书商城项目实战(附源码+文档)
  • springboot034在线商城系统设计与开发-代码(论文+源码)_kaic
  • 「UCD」ComfyUI设计提效工具
  • 滚雪球学Redis[9.1讲]:Redis常见问题排查指南:解决错误、优化性能与确保数据一致性
  • sql高级
  • APIJSON 为零代码提供了新的思路
  • H-TCP 的效率和公平性
  • oracle19c的k8s部署
  • 【可答疑】基于51单片机的智能空调(含仿真、代码、报告、演示视频等)
  • Java密封类(Sealed Classes)增强详解
  • WPF入门_04绑定
  • 《黑神话悟空》各章节boss顺序汇总
  • 2024.10月22日- MySql的 补充知识点
  • 《Python游戏编程入门》注-第2章2
  • 【数据结构与算法】走进数据结构的“时间胶囊”——栈
  • go开发过程中mapstructure使用,
  • Windows性能监控与调优:让电脑运行如飞
  • vulnhub靶场之digitalworld.local DEVELOPMENT