什么是 MVCC?
2023年12月22日大约 3 分钟MySQL
针对
MySQL
数据库的innodb
引擎
详细分析请看《MySQL 是怎么运行的:从根儿上理解 MySQL》中的 MVCC 部分
基本概念
MVCC
(Multi-Version Concurrency Control
,多版本并发控制)
指的是在 RC
、RR
隔离级别下执行普通 SELECT
操作时访问记录的版本链的过程,这样子可以使不同事务的 读-写
、写-读
操作并发执行,从而提高系统性能
实现原理
核心就在于 undo log
和 ReadView
(一致性视图)
- 通过
undo log
来保存多版本的数据 - 通过
ReadView
保存当前活跃的事务列表
首先我们知道使用 innodb
引擎的表中,它的聚簇索引记录会包含 3 个隐藏列
row_id
: 非必需,表中如果存在主键或非Null
的Unique
键时不包含:trx_id
:当有事务对某条聚簇索引记录进行改动时,会把该事务的事务 id
赋值给trx_id
roll_pointer
:每次对聚簇索引记录进行改动时,都会把旧的版本写入到undo 日志
中,通过roll_pointer
这个指针就可以找到该记录修改前的信息
行的每一次改动都会生成undo log
,久而久之,就会形成一条版本链
而 ReadView
呢,它最主要的目的就是判断版本链中的哪个版本是当前事务可见的
它包含 4 个重要的内容
m_ids
:生成ReadView
时,活跃的读写事务的事务 id
列表min_trx_id
:生成ReadView
时,活跃的读写事务中最小的事务 id
,也就是m_ids
的最新值max_trx_id
:生成ReadView
时,系统应该分配给下一个事务的id
值
max_trx_id并不是m_ids中的最大值creator_trx_id
:生成该ReadView
的事务的事务 id
只有在对表中的记录做改动时(执行 INSERT、DELETE、UPDATE 这些语句时)才会为事务分配事务 id,否则在一个只读事务中的事务 id 值都默认为 0
在执行 SELECT
语句时,innodb
引擎会生成一个 ReadView
,随后按照特定的规则决定具体能看到数据的哪个版本
- 如果被访问记录的
trx_id
等于creator_trx_id
,则意味着当前事务在访问自己修改过的版本,可以被当前事务访问 - 如果被访问记录的
trx_id
小于min_trx_id
,则意味着在查询前事务已经提交,可以被当前事务访问 - 如果被访问记录的
trx_id
大于等于max_trx_id
,则意味着在生成ReaView
后事务才开启,不可以被当前事务访问 - 如果被访问记录的
trx_id
在min_trx_id
与max_trx_id
之间- 在
m_ids
中,事务仍然活跃,不能被访问 - 不在
m_ids
中,事务已经被提交,可以被访问
- 在
按照这个规则,如果某个版本的数据对当前事务不可见的话,那就顺着版本链找到上一个版本的数据,继续按照上述规则判断可见性,直到最后一个版本
RC 和 RR 事务隔离级别的区别
直接说结论
RC
:每次读取数据前都生成一个ReadView
RR
:只在事务第一次执行查询语句时才会生成一个ReadView
所以,RR
隔离级别下,每次查询数据时用的都是同一个 ReadView
,才能做到可重复读
而在 RC
隔离级别下,每次查询时,都可能有其他事务正常提交,导致 ReadView
中的 max_trx_id
,m_ids
发生变化,于是可以读取到已经提交的数据