MySQL的MVVC是个什么东东

760

MVVC是什么

MVVC,全称Multi-Version Concurrency Control

多版本的并发控制,Multi-Version Concurrency Control,是一个可以提升数据库并发读写性能的技术。

一般的,如果对数据的库表的一行记录进行读写操作,为了保证数据的一致性,往往需要对这一行记录进行加锁操作。而加锁带来的问题就是开销变大,性能降低。而MVVC便是对这一问题提出的一种改进策略。

快照读和当前读

首先,我们先了解一下两个概念——快照读和当前读。

当前读

当前读可以理解为,所有的当前读操作都是针对的数据库最新版本的数据,在操作的时候会对资源加悲观锁,防止其他事务对数据进行修改。

如delete、update、insert、select for update、select lock in share mode等操作均是当前读

需要注意的时,在串行化的事务隔离级别下,所有的操作均是当前读

快照读

快照读的实现是基于MVVC的,读取的可能是某个版本的快照数据。

MVCC

数据库中有哪些并发场景?

  • 读-读 读操作不会造成数据一致性问题,也没有并发控制的需要
  • 读-写 可能造成数据不一致,需要对线程安全进行控制,否则会造成脏读、幻读、不可重复读的错误
  • 写-写 多线程存在问题,可能会造成数据丢失
MVCC能解决什么场景下的问题?
  • 解决读-写场景下的并发问题,可以实现读写均不会阻塞,解决脏读、幻读、不可重复读的问题
  • 不可解决写-写场景下的并发控制问题,一般可结合乐观锁或者悲观锁来实现
MVCC如何实现并发控制的?

其实现主要依靠undo日志,版本链,Read View三个技术手段。

undo日志

undo可以理解为每次针对记录行修改时,原数据的备份。每一次针对原纪录的修改都会生成一个undo日志,将原数据拷贝到日志中记录起来

  • 用于事务回滚
  • 是的每个事务均有自己特有的日志记录集合

undo日志一般分为插入日志和更新日志。插入日志是执行insert操作生成的日志,在事务回滚时需要使用,在事务提交后可以丢弃掉;更新日志不仅在事务回滚的时候需要,在快照读的时候也需要,不能随便删除

版本链

数据表记录的每一行均有3个隐藏列

  • db_trx_id 事务id

  • db_roll_pointer 回滚指针,指向上一个版本

  • db_row_id 隐藏的自增主键

img

这是一个简单的示例图。

img

很容易理解,每次修改都会undo日志,通过版本指针将这些日志串联起来,形成版本链。

Read View

读视图可以理解为快照读是生成的整个数据库系统的一个快照。其可以用来做可见性判断。因为每一个事务均有唯一的id,可以用此id来控制此事务可以看到的数据,可以是最新版本的,也可以是历史版本的。

其有如下几个参数:

  • trx_ids 目前系统中未提交的事务id集合
  • low_limit_id 最大事务版本号加1
  • up_limit_id 处于活跃状态中的最好事务版本号
  • creator_trx_id 创建read view的事务版本号

可见性判断代码

img

MVCC和事务隔离级别的关系

MVCC如何实现RR和RC的隔离级别

在RC的隔离级别下,只要提交了都可以被其他事务读取到,每一个快照读均会生成一个最新的read view

在RR的隔离级别下,为保证可重复读,每一个事务只在第一个快照读的时候才生成最新的read view,后续的快照读均不在生成快照读了,直接使用第一次快照读生成的read view,保证每一次查询结果都是一样的

那么如何解决幻读的问题?

快照读:按照MVCC的机制,可以解决幻读的问题

当前读:next-key锁(行锁+gap锁)