【高并发基础】理解 MVCC 及提炼实现思想

20 篇文章 0 订阅
7 篇文章 0 订阅

1. 前言

MVCC 在 MySQL、Oracle、PostgreSQL 都有应用,用于实现事务的隔离特性。现在结合 《MySQL是怎样运行的》的内容理解、归纳、整理下MVCC的实现及思想。

2. MVCC 概念

Multiversion Concurrency Control 对版本并发控制。
对于同一行数据,会根据不同事务的DML操作参生不同的版本,让不同事务各自维护自己能看到的版本从而做到事务隔离。

2.1 MVCC 版本链

每次操作数据库都会生成日志,那么就可以把同一条记录的多次操作记录按时间顺序链接起来。
在这里插入图片描述

  • 算法模型
    在这里插入图片描述

2.2 MVCC trx_id

按事务开启的时间顺序,为事务颁发一个Id,从而维护“版本”。是讨论MVCC实现的基础。

2.3 MVCC Read View

光有日志记录还不够,每个事务应该要维护自己的 “视野范围”。也就是当前事务到底能看到什么版本的数据,建立 Read View,并与版本链协作,就能约束事务的视野,从而实现隔离。
Read View 包含:

  1. m_ids
  2. min_trx_id
  3. max_trx_id
  4. creator_trx_id

Read View 里面有多个属性,他们是分别用于解决不同问题的。

3. 提出问题

如何控制当前事务读不到其他事务 未提交 的数据

4. 解决问题

我们把日志的 trx_id 与 区间 [min_trx_id, max_trx_id ] 的命中关系罗列出来,用于后续讨论问题

trx_id >= Read View. max_trx_id
Read View. max_trx_id  > trx_id  >=  Read View. min_trx_id
trx_id < Read View. min_trx_id

4.1 不读未提交的数据

4.1.1 没有并发

事务生成了 Read View 之后,对数据行进行读取,发现日志中有

trx_id >= Read View. max_trx_id  // max_trx_id 表示下一个事务颁发的id, 所以取等号时,该记录也不属于自己的事务

则说明该日志发生在建立 Read View 之后,并且生成该日志的事务是在当前事务之后开启。
至此,我们能够得到一个信息:该日志发生在当前事务开启之后,直接舍弃

trx_id < Read View. min_trx_id

这个比较简单,直接读即可。由于较新的日志一定会置顶,读到 trx_id < Read View. min_trx_id 立马返回数据即可。


4.1.2 有并发

新引入两个参数

  • min_trx_id: 当前所有事务中,活跃的(未提交的)事务中 trx_id 最小的一个
  • m_ids: 当前所有事务中,活跃的(未提交的)事务列表

事务生成了 Read View 之后,对数据行进行读取,发现日志中有

Read View. max_trx_id  > trx_id  >=  Read View. min_trx_id

说明该日志的事务跟建立 Read View 的时机挨得很近,我们还是可以考虑一下这条日志。具体怎么考虑呢?
m_ids 在 Read View 中负责记录建立 Read View 那一刻的 活跃事务
如果日志中的 trx_id 不在活跃事务列表,侧面说明该日志的事务已经提交,则可以读取它,否则不读。


5. MVCC DML 会生成新的 Read View 吗?

并不会,DML语句操作语句交给锁处理了,MVCC只是控制读取的数据的版本。
那么DML跟Read View无关吗,当然也不是,使用 creator_trx_id 登记自己操作了的数据。
如果creator_trx_id == 日志中的trx_id,则是自己操作的数据,直接读取即可

6. MySQL RC 及 RR 使用 MVCC 的时机

  • RC
    MySQL 会对每个查询语句生成 Read View。

  • RR
    RR 的隔离级别比 RC 高,其中隔离性的提高本质上就是调整了 Read View 创建的时机
    第一个查询语句生成 Read View,后续的所有查询都 复用这个 Read View,所以每次读取的值,都来源于同一个版本。

7. 提炼 MVCC 的思想

MVCC 用 ReadView 的创建实现事务隔离,同时又尽最大努力去读最新的数据。建立 Read View 时,登记一刹那的事务并发情况。读取具体数据库记录的时候,有日志文件和 Read View共同决策是否信任此日志的数据。回顾以下模型:

在这里插入图片描述

上文说的日志,是因为日志承载的是一个思想,MySQL是用 undo log支撑MVCC的,而PostgreSQl则不是。

8. 后记

早期写的 InnoDB 如何避免脏读和不可重复读,是不严谨的地方,现在纠正过来,希望持续学习,不断进步。
MVCC 给我的启示是,我们可以尝试用区间命中的思想去分解问题,当命中关系被完全覆盖,我们可以认为问题被分解完成。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值