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 则会对所有读取的行都会加锁。