MVCC版本并发控制

MVCC 多版本并发控制

MVCC 是一种并发控制的方法,实现对数据库的并发访问,提高读并发效率。

在InnoDB中就是指:在已提交读(RC)和可重复读(RR)这两种隔离级别下的事务对于SELECT操作时,会访问版本链中的记录。

版本链

在InnoDB中,聚簇索引记录中有两个必要的隐藏列:

trx_id:这个id用来存储的每次对某条聚簇索引记录进行修改的时候的事务id。

roll_pointer:每次对哪条聚簇索引记录有修改的时候,都会把老版本写入 undo 日志中。roll_pointer就是存了一个指针,它指向这条聚簇索引记录的上一个版本的位置,通过它来获得上一个版本的记录信息。(注意插入操作的 undo 日志没有这个属性,因为它没有老版本)

ReadView

已提交读和可重复读的区别就在于它们生成ReadView的策略不同。

ReadView中主要就是有个列表来存储我们系统中当前活跃着的读写事务,也就是还未提交的事务。通过这个列表来判断记录的某个版本是否对当前事务可见。

当前列表里的事务id为[50-90]
如果要访问记录版本的事务id为30,比当前列表最小的id小,说明这个事务已经提交过了,所以是可以访问的。
如果要访问的记录版本的事务id为70,在列表最大与最小值之间,此时需要判断事务是否在列表内,如果在,说明事务未提交,不能访问;如果不在,说明事物已提交,版本可以被访问。
如果要访问的记录版本的事务大于列表中最大id,那说明版本是在ReadView之后生成的,不能访问版本。

这些记录都是去版本链里面找的,先找最近记录,如果最近这一条记录事务id不符合条件,不可见的话,再去找上一个版本比较当前事务的id和这个版本事务id看能不能访问,以此类推直到返回可见的版本或者结束。

已提交读隔离级别下的事务在每次查询的开始都会生成一个独立的ReadView,而可重复读隔离级别则在第一次读的时候生成一个ReadView,之后的读都复用之前的ReadView。

实际上,MVCC解决了数据库采用悲观锁这样性能不佳的方式去解决读-写冲突问题,而提出的解决方案,所以在数据库中,可以采用以下组合最大程度的提高数据库并发性能。

  • MVCC + 悲观锁
    MVCC解决读写冲突,悲观锁/乐观锁 解决写写冲突

什么是当前读和快照读?

当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。

快照读:像不加锁的select操作就是快照读。快照读的前提是隔离级别不是串行级别,串行级别下的快照读会退化成当前读。基于提高并发性能的考虑,快照读的实现是基于多版本并发控制,即MVCC。

MVCC其实就是为了实现不加锁解决读-写冲突,而这个读指的就是快照读。当前读实际上是一种加锁的操作,是悲观锁的实现。

posted @ 2021-11-30 21:52  Leejk  阅读(54)  评论(0编辑  收藏  举报