面试不可或缺的MVCC

2022-05-05 12:27:47 浏览数 (1)

面试不可或缺的MVCC

什么是MVCC? 以及它的作用

“MVCC,即多版本并发控制。顾名思义,MVCC就是通过对数据做多版本管理,来做到读不加锁,读写不冲突,进而提高数据库并发性能。在Innodb存储引擎中MVCC用来实现RR和RC两种事物隔离级别,即保证在这两种隔离级别下进行读操作时,读到的总是我们想要的数据。 ”

预设行数据

如下图所示,插入一条id为1,name为大西瓜的记录

快照读和当前读

  • 快照读:读取的是版本链中的可见版本,通过MVCC实现并发控制,SELECT操作;
  • 当前读:读取的是最新版本,通过Next-Key锁来保证该记录的正确性,INSERT/UPDATE/DELETE这些可能会导致数据库数据更新的操作。

MVCC的原理支持

  • 隐藏字段
  • UndoLog
  • ReadView

隐藏字段:

  • row_id : 在Innodb引擎下,当我们不手动指定主键时,由于Innodb是基于B 树索引的,Innodb会自动生成一个大小为6B的隐藏字段,来充当我们的主键(聚簇索引)用来进行生成B 树索引组织数据。
  • trx_id : 表示修改这条记录的事务id,大小6B
  • roll_pointer : 回滚指针,指向Undo log中,该记录之前的版本数据,大小为7B

此时我在上面提到的预设行,实际上会是下图这种格式,roll_pointer为null是因为INSERT操作的记录没有更早的版本,即不存在该属性,但是为了大家理解方便,这里表示为null:

UndoLog:

“回滚日志,版本快照是保存在Undo日志中的,版本快照之间又是通过回滚指针roll_pointer链接起来的,这样就生成了版本链。 ”

假设存在两个id为100、200的事务对预设字段进行了更新操作,操作流程为:

trx_id=100

try_id=100

Begin

Begin

update user set name = "小西瓜" where id = 1;

update user set name = "西瓜籽" where id = 1;

Commit

update user set name = "大冬瓜" where id = 1;

upda te user set name = "小冬瓜" where id = 1;

Commit

则其对应生成的版本链应当为:

ReadView:

MVCC之所以可以做到版本并发控制,很大程度上是依托于ReadView。我们前面提到过MVCC是用来实现RR和RC两种事务隔离级别的,当然在这两种隔离级别下的ReadView生成策略也是不同的:

  • RR级别下事务只在第一次进行快照读时创建ReadView视图,保证了可重复读这一特性。
  • RC级别下事务每次进行快照读都会创建新的ReadView视图,保证了事务可以看到其他事务修改并提交后的数据,保证了读已提交这一特性

ReadView的几个重要属性:

  • trx_ids:表示在创建ReadView时,系统中未提交(活跃)事务版本号集合
  • min_trx_id:表示在创建ReadView时,系统中未提交事务中最小版本号
  • max_trx_id:表示在创建ReadView时,系统中应该分配给下一个事务的id值,即当前系统中已创建的最大事务版本号 1;
  • creator_trx_id:创建当前ReadView的事务版本号,只有INSERT/DELETE/UPDATE这些可能存在对数据库发生修改的操作才会分配事务id,只读的SELECT事务的id值为0;

ReadView的匹配规则:

  • 被访问版本的trx_id < min_trx_id,表示生成该版本的事务在当前事务生成ReadView前就提交了,可见
  • 被访问版本的trx_id >= max_trx_id,表示生成该版本的事务在当前事务生成ReadView后才开启的,不可见
  • 被访问版本的trx_id ∈ [min_trx_id,max_trx_id),这时候分三种情况讨论::trx_id ∈ trx_ids,表示生成该版本的事务还未提交,不可见 :特例:trx_id = creator_trx_id,表示当前事务正在访问自己修改过的版本记录,可见 :trx_id ∉ trx_ids,表示生成该版本的事务已经提交,可见

0 人点赞