3

MySQL笔记之一致性视图与MVCC实现 - 邴越

 1 year ago
source link: https://www.cnblogs.com/binyue/p/17296542.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

一致性读视图是InnoDB在实现MVCC用到的虚拟结构,用于读提交(RC)和可重复度(RR)隔离级别的实现。

一致性视图没有物理结构,主要是在事务执行期间用来定义该事物可以看到什么数据。

 

524341-20230407161748862-1610998319.png

一、Read View

事务在正式启动的时候我们会创建一致性视图,该一致性视图是基于整个库的。

1、transaction id

InnodDB的每个事务都有一个唯一的事务ID,叫做transaction id,该ID在事务开始的时候向InnoDB申请,并且按照申请顺序严格递增。

每行数据都会有多个版本,每次事务更新数据的时候都会生成一个新的数据版本,并且把transaction id赋值给这个数据版本的事务id,称为row trx_id。

524341-20230407160922386-1923226070.png

上图是一条行数据的多个版本,最新的版本是 V4。

其中U3、U2、U1代表的是undo log,V1、V2、V3在物理上并不真实存在,而是在需要的时候通过V4配合undo log计算获得。

2、ReadView如何工作

ReadView中主要包含4个比较重要的内容:

  • m_ids:表示在生成ReadView时当前系统中活跃的读写事务的事务id列表。
  • min_trx_id:表示在生成ReadView时当前系统中活跃的读写事务中最小的事务id,也就是m_ids中的最小值。
  • max_trx_id:表示生成ReadView时系统中应该分配给下一个事务的id值。
  • creator_trx_id:表示生成该ReadView的事务的事务id。
524341-20230407160945189-2030808542.png

在访问某条记录时,按照下边的步骤判断记录的某个版本是否可见:

  • 如果被访问版本的trx_id属性值与ReadView中的creator_trx_id值相同,意味着当前事务在访问它自己修改过的记录,所以该版本可以被当前事务访问。
  • 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id值,表明生成该版本的事务在当前事务生成ReadView前已经提交,所以该版本可以被当前事务访问。
  • 如果被访问版本的trx_id属性值大于ReadView中的max_trx_id值,表明生成该版本的事务在当前事务生成ReadView后才开启,所以该版本不可以被当前事务访问。
  • 如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间,那就需要判断一下trx_id属性值是不是在m_ids列表中,如果在,说明创建ReadView时生成该版本的事务还是活跃的,该版本不可以被访问;如果不在,说明创建ReadView时生成该版本的事务已经被提交,该版本可以被访问。

3、记录未提交的场景

如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到下一个版本的数据,继续按照上边的步骤判断可见性,依此类推,直到版本链中的最后一个版本。

如果最后一个版本也不可见的话,那么就意味着该条记录对该事务完全不可见,查询结果就不包含该记录。

二、不同隔离级别下生成ReadView区别

在MySQL中,READ COMMITTED和REPEATABLE READ隔离级别的区别就是它们生成ReadView的时机不同。

1、可重复读隔离

MySQL的默认隔离级别是RR(可重复读),按照 可重复读的语义,每个事务启动的时候只能看到已经提交的事务,并且在本事务执行的过程中,不可以读取到其他事务的更新操作。

在InnoDB 中,为每个事务构造了一个  当前事务ID数组的快照,就是记录事务开启时,当前正在执行的事务ID 的集合。数组里面 trx_id 最小的记为 低水位,trx_id 最大的 + 1 记为高水位。如下图所示:

524341-20230407161039073-1127404762.png

对于一个新事务而言,所读取到的记录版本的 trx_id 可能有以下几种情况:

1、在绿色区域:说明数据版本在事务开始前已提交,当前版本是可见的。

2、在红色区域:说明数据版本在事务开始后变更的,当前版本是不可见的。

3、在橙色区域:包含 2 种情况。

A、如果 数据版本的 trx_id 在数组中,说明是正在执行的事务,不可见。

B、如果 数据版本的 trx_id 不在数组中,说明是已经提交的事务,可见。

可以看出,InnoDB 利用了 UndoLog 数据多版本的特点,实现了快速创建快照的能力。

2、读已提交

对可重复读来说,事务只有在第一次进行读操作时才会生成一个ReadView,后续的读操作都会重复使用这个ReadView。

也就是说,如果在此期间有其他事务提交了,那么对于可重复读来说也是不可见的,因为对它来说,事务活跃状态在第一次进行读操作时就已经确定下来,后面不会修改了。

对读已提交来说,事务中的每次读操作都会生成一个新的ReadView。

也就是说,如果这期间某个未提交事务Commit了,那么它就会从ReadView中移除,添加到已提交事务中,这样确保RC级别下事务每次读操作都能读到已经提交的数据。

参考资料:

《高性能 MySQL》第一章第 4 节;

极客时间《MySQL 实战 45 讲》


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK