MVCC多版本并发控制

MySQL中大多数事务型的存储引擎都不是简单的行级锁。为了提高并发性,他们一般会采用多版本并发控制(MVCC,一种行级锁的变种)来使很多情况下在避免加锁的情况下就实现并发操作,从而是的系统开销更低。

MySQL的InnoDB存储引擎的MCVV,是通过在每行记录后面保存两个隐藏的列来实现。一个保存行的创建时间,另一个保存过期时间。当然这里所说的时间并不是实际时间,是系统版本号。数据库系统在每开始一个事务,其系统版本号就会自动递增。一个事务开始时刻,事务会去当前的系统版本号作为当前事务的事务版本号,用来和查询到的每行记录的版本号做比较。

id fields … create_version delete_version
1 …. 1
2 …. 2 3

具体实现

Repeatable read 隔离级别下,MVCC具体操作:

Select 操作:

a. InnoDB 只查找版本号小于当前事务版本号的行(即,行的系统版本号小于或者等于当前事务的系统版本号),以确保当前事务读取到的行,要么是当前事务开始之前就已经存在的行,要么就是当前事务插入或者修改过的行。
b. 行的删除版本号要么未定义,要么大于当前事务的版本号。这样可以确保当前事务读取到行,在事务开始之前为被删除。

只有同事符合上述两个条件的记录,才能被作为查询结果被返回。

Insert 操作:

InnoDB为新插入的行保存当前事务的版本号作为行版本号。

Delete 操作:

InnoDB为删除的每一行记录保存当前的事务版本号作为行删除标识。

Update 操作:

InnoDB会插入一条新纪录,保存当前事务版本号作为改行的行版本号,同事保存当前的事务版本号到原来的行作为行删除标识版本号。

多版本并发控制优缺点

优点

通过两个额外的版本号,能使大多数读操作都可以不用加锁,从而使得查询性能更好。

缺点

每行记录多需要做存储两个版本号,需要浪费额外的存储空间。

TIPS:
MVCC,只在Repeatable read 和read committed两个隔离级别下工作。其他两个隔离级别都和MVCC不兼容,因为 read uncommitted总是读取最新的行,而不是符合当前事务版本号的行,而 serializable 则会对所有读取的行都会加锁。