MVCC版本控制
2023年8月13日大约 3 分钟
MVCC版本控制
- MVCC多版本并发控制 ,它是数据库管理系统一种常见的并发控制。
- 我们知道并发控制常用的是锁,当线程要对一个共享资源进行操作的时候,加锁是一种非常简单粗暴的方法
- 这种锁是一种 悲观 的实现方式,也就是说这会给其他事务造成堵塞,从而影响数据库性能。
MVCC 只是一种 乐观 的实现形式
,它是通过 一种 可见性算法 来实现数据库并发控制
MVCC 的两种读形式
在讲 MVCC 的实现原理之前,我觉很有必要先去了解一下 MVCC 的两种读形式
快照读
:读取的只是当前事务的可见版本,不用加锁- 而你只要记住 简单的 select 操作就是快照读(select * from table where id = xxx)
当前读
:读取的是当前版本,比如 特殊的读操作,更新/插入/删除操作
MVCC 的实现原理
MVCC隐藏字段
- MVCC 使用了“三个隐藏字段”来实现版本并发控制
RowID | DB_TRX_ID | DB_ROLL_PTR | id | name | password |
---|---|---|---|---|---|
自动创建的id | 事务id | 回滚指针 | id | name | password |
RowID
:隐藏的自增ID
,当建表没有指定主键,InnoDB会使用该RowID创建一个聚簇索引DB_TRX_ID
:最近修改(更新/删除/插入)该记录的事务ID
DB_ROLL_PTR
:回滚指针,指向这条记录的上一个版本
- 其实还有一个删除的flag字段,用来判断该行记录是否已经被删除
MVCC 的 可见性算法
undoLog
: 事务的回滚日志,是 可见性算法 的非常重要的部分,分为两类。insert undo log
:事务在插入新记录产生的undo log,当事务提交之后可以直接丢弃
update undo log
:- 事务在进行
update 或者 delete 的时候产生的 undo log
,在快照读的时候还是需要的,所以不能直接删除 - 只有当系统没有比这个log
更早的read-view了的时候才能删除
- ps:所以长事务会产生很多老的视图导致undo log无法删除 大量占用存储空间。
- 事务在进行
read-view
: 读视图,是MySQL秒级创建视图的必要条件- 比如一个事务在进行 select 操作(快照读)的时候会创建一个 read-view ,这个read-view 其实只是三个字段。
alive_trx_list
(我自己取的):read-view生成时刻系统中正在活跃的事务id。up_limit_id
:记录上面的 alive_trx_list 中的最小事务id。low_limit_id
:read-view生成时刻,目前已出现的事务ID的最大值 + 1。
可见性算法规则
1)首先比较这条记录的
DB_TRX_ID(最近修改事务ID)
是否是 小于等于up_limit_id(read-view生成时刻系统中正在活跃的事务id)
如果满足,那么说明当前事务能看到这条记录
,如果大于则进入下一轮判断
2)然后判断这条记录的
DB_TRX_ID(最近修改事务ID)
是否 大于等于
low-limit-id(read-view生成时刻,目前已出现的事务ID的最大值+1)
如果大于等于则说明此事务无法看见该条记录
,不然就进入下一轮判断
3)判断该条记录的
DB_TRX_ID(最近修改事务ID)
是否在活跃事务的数组中
如果在则说明这条记录还未提交对于当前操作的事务是不可见的
,如果不在则说明已经提交,那么就是可见的
