InnoDB之MVCC精讲

MVCC精讲

定义: MVCC,也叫多版本并发控制,顾名思义,是通过维护数据的多个版本来实现的,是一个”为了提升并发性能“而提出来的一个概念,它允许读操作和写操作并发执行,而不会相互阻塞。由于没有正式的规范,所有每个存储引擎和数据库系统实现的方式都是有差异的。

下面主要介绍InnoDB版MVCC。

MVCC数据结构

MVCC的实现主要依赖于以下数据结构

  • 版本链(Version Chain)

    当一行数据被修改时,它不会直接覆盖原始数据,而是创建一个新的数据版本,并将新版本与旧版本通过指针链接起来,形成一个版本链。这样,不同的事务就可以读取到不同版本的数据,从而实现了并发控制

  • ReadView

    ReadView是MVCC中一个非常重要的数据结构,它表示了一个事务在某一时刻能够看到的数据版本范围。当一个事务开始执行时,它会根据当前活跃的事务列表生成一个ReadView,用于确定哪些版本的数据对该事务是可见的。

  • Undo日志

    Undo日志用于保存数据的旧版本信息。当事务进行更新或删除操作时,旧的数据版本会被保存在Undo日志中。这样,如果需要回滚事务或读取旧版本的数据,就可以通过Undo日志来恢复或获取。

  • 活跃事务列表

    活跃事务列表记录了当前系统中所有未提交的事务。这个列表用于生成ReadView,以确定哪些事务的版本对当前事务是可见的。当新的事务开始时,它会被添加到这个列表中;当事务提交或回滚时,它会被从这个列表中移除

  • 行级锁

    虽然MVCC本身不直接依赖于行级锁来实现并发控制,但在某些情况下,行级锁可以与MVCC结合使用,以提供更高级别的并发性能。行级锁可以确保在修改数据时,只有被锁定的行会被阻塞,而其他行仍然可以被其他事务并发访问


在聚簇索引中,每条记录都有额外的三个隐藏字段,分别是db_row_iddb_trx_iddb_roll_pointer

  • db_row_id:当定义了主键时,db_row_id 就是主键id,没有指定时,db_row_id 就是找到的第一个唯一的非空索引列的id,如果唯一的非空索引也没有,那么会自动生成一个主键
  • db_trx_id:事务的id
  • db_roll_pointer:指向undo.log中历史版本数据的指针

在这里插入图片描述

下面重点来看read view 的数据结构

read view 结构

ReadView是一个数据结构,它包含了生成该视图时活跃的事务信息。ReadView 用于确定哪些行版本对当前事务是可见的

read view 中包含了以下四个关键组成部分:creator_trx_idtrx_idsup_limit_id low_limit_id,它们各自的作用如下

creator_trx_id

  • 这是创建当前read view的事务的版本号。它标识了read view的“所有者”或创建者,确保该事务能够看到自己所做的修改,这个应该很好理解。

trx_ids

  • 这是一个集合,也就是上面说的 活跃事务列表,它包含了当前系统中所有活跃(即未提交)的事务的ID。这些事务ID代表了当前正在执行且尚未完成的事务。这些事务的ID是在 read view 创建时活跃的,因此它们所做的修改对于当前事务来说是不可见的。

up_limit_id

  • 这是“系统正处于活跃事务最小版本号”。换句话说,它标识了在read view 创建时,系统中最早开始的一个活跃事务的版本号,也就是从 trx_ids 中选择出来的最小事务ID。这有助于确定哪些旧版本的数据对当前事务是可见的。

low_limit_id

  • 通常被设置为creator_trx_id + 1,或者是创建当前 read view 时系统当前分配的最大事务ID加1。由于事务版本号在事务开始时分配,并且随着新事务的创建而递增,low_limit_id 确保了任何在read view创建之后开始的事务的修改对当前事务都是不可见的

这四个组成部分共同工作,使得InnoDB能够确定一个事务在执行查询时能够看到哪些数据版本。通过比较这些值和当前正在执行的事务的版本号,InnoDB能够确保每个事务都看到一个一致的数据快照,即使其他事务同时在进行修改。这种机制是实现MVCC的核心,它允许高并发的数据库操作,同时保证了数据的一致性和隔离性


可见性规则

访问某条记录的时如何判断该记录是否对当前事务可见呢?看看下面的规则

  • 如果被访问记录的事务id = creator_trx_id,说明当前事务在访问自己修改过记录,是可见的

  • 如果被访问记录的事务id < creator_trx_id,并且不在trx_ids 中,或者说小于 up_limit_id,说明在当前事务创建read view 之前该记录就已经被提交,因此对当前的事务是可见的

  • 如果被访问记录的事务id >= low_limit_id,说明是在当前事务创建read view之 后才新建的事务,那么对当前事务是不可见的

  • 如果被访问记录的事务id 在 > up_limit_id 并且 < low_limit_id,说明这个事务在当前事务创建read view 时还没有被提交。因为活跃事务列表是实时的,当

    • 被访问记录的事务id在trx_ids 中,说名该事务还没有被提交,对当前事务是不可见的
    • 被访问记录的事务id 不在trx_ids 中,说名该事务已经被提交,那么对当前事务是可见的

隔离级别

MVCC只在隔离级别为:可重复读,读已提交 下工作,因为在 READ UNCOMMIT 隔离级别下,每次读取的都是最新的数据,而不是符合当前事务版本的数据行。在 SERIALIZABLE 隔离级别下,事务都是串行执行,根本不存在并发。

**rc级别:**每次操作都会创建新的read view

**rr级别:**仅在第一次操作时生成read view,后面一直用这个read view


MVCC的优缺点

优点: 提高了并非性能,使得大多数读操作可以不用加锁
缺点:要维护系统版本号,需要额外的存储空间、检查和维护工作

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

罗罗的1024

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值