MySQL MVCC的详解之Read View

文章目录

    • 概要
    • 一、基于UNDO LOG的版本链
        • 1.1、行记录结构
        • 1.2、了解UNDO LOG
        • 1.3、版本链
    • 二、Read View
        • 2.1、判定机制
    • 三、参考

概要

在上文中,我们提到了MVCC(Multi-Version Concurrency Control)多版本并发控制,是通过undo log来实现的。那具体是如何实现的呢?将在本文一一道来。

MVCC是为了实现非阻塞读,即提高数据库并发读能力的一种机制。

通常来说,A事务正在修改数据行X,在修改未结束前,B事务要读数据行X,为了避免读到脏数据,B就会被阻塞,直到A事务修改完数据行X,MVCC很好的避免了这种情况的发生。

MVCC是通过保存数据在某个时间点的快照来实现的,即保存一个数据行的多个变更版本(空间换时间)。这些版本就是undo log了,每一行的变更记录就存在undo log中,通过链表联系在一起,构成了一个完整的版本链,供MVCC实现非阻塞读。

例如在可重复读隔离级别下,A事务正在修改数据行X,在修改数据行X前会把其当前记录插入到版本链中,B事务要读数据行X就到版本链中找符合的,这样B就不会被阻塞了。

ps:MySQL的MVCC只作用于在REPEATABLE READ和READ COMMITED两个隔离级别下执行普通的SELECT操作。

在高性能MySQL第三版一书中对MVCC的操作描述如下:
高性能MySQL第三版一书中对MVCC的操作描述下面来一起探索下具体实现吧。

本文背景:MySQL InnoDB存储引擎。

一、基于UNDO LOG的版本链

在了解版本链之前,首先看一下InnoDB存储引擎的行记录。

1.1、行记录结构

提到MySQL的行记录,肯定会想到行ID、用户数据列等内容,除了这些信息外,还有一些隐藏信息,比如事务ID、回滚指针等其他额外信息,那我们可以得出下图:
MySQL行记录结构简单示意图
其中事务ID(trx_id)、回滚指针(rollback_ptr)是本文要讲的核心。

ps:InnoDB的行记录是存储在聚族索引中的

1.2、了解UNDO LOG

                                            MySQL undo log结构示意图

MySQL undo log结构示意图

MySQL的undo log分为两大类:

  1. insert undo:insert 操作产生的,记录了table_id、trx_id、主键各列数据等信息。
  2. update undo:update和delete操作产生的,

虽说update和delete操作产生的undo log都会记录到update undo这个大类,但其记录内容是有很大差距的。
delete操作产生的undo log会记录table_id、trx_id、rollback_ptr、主键各列数据等信息,而update操作产生的undo log会记录更新table_id、trx_id、rollback_ptr、被更新列旧值、主键各列数据等信息。

ps:可以看到undo log中并没有记录用户列数据

1.3、版本链

我们现在在test库下有一个test表:
MySQL 测试表下面我们经过一系列插入,删除,更新来演示版本链的变迁:
假设当前全局trx_id = 101。

  1. 插入一条数据
insert into test (id,num,name,key_id) values (1,1,"bob",11);

此时有:
插入一条数据

  1. 更新数据
    1)令id=1的数据name=tom
update test set name = "tom" where id = 1;

此时有:
更新一条数据
2)令id=1的数据name=join

update test set name = "join" where id = 1;

此时有:
更新一条数据

  1. 删除数据,删除id=1的数据
delete from test where id = 1;

此时有:
删除一条数据
如上图,在对id=1这一条记录的插入,更新,删除的过程中构建了一个版本链。其中删除操作,只是在聚簇索引上的记录中打了删除标记,并不会立即删除,而是当没有Read View持有该事务ID时才会有purge线程去真的去删除,之后这块空间才能被使用,为什么不能立即删除呢,主要是因为undo log中并不保存所有的用户列数据,甚至不保存,都是基于聚簇索引中的记录行,在结合undo log内容,在回滚过程中构造某个版本的数据。

另外,我们在1.2小节中强调了 undo log中并不记录用户列数据,这里只是为了表示方便才画了出来,其实MySQL是基于聚簇索引上的记录内容,通过从聚簇索引上的记录roll_ptr开始,依次回滚,直到遇到符合要求的事务ID,构造出最终数据。

假设第二次更新操作开始但未提交时,有个trx_id=107的事务要读id=1的数据,此时发现ID=1的数据trx_id=106且处于活跃状态,则需要沿着版本链回滚,当遇到trx_id=102的记录,结合聚簇索引上的记录和trx_id=102的undo记录,构造出trx_id=102的完整数据,对于trx_id=107的事务来说,该事务是已提交的事务,则读取即可。其实这就是Read View了,详情请看下一章节。

二、Read View

对于READ COMMITED隔离级别,需要读已经提交的数据,那当A事务修改完聚簇索引上的记录X后尚未提交,此时B事务读取记录X,按照定义,此时聚簇索引上的记录是不允许读取的,如何判定呢?就依赖Read View机制了

对于REPEATABLE READ隔离级别,需要重复读数据,那当A事务读取记录X后,B事务修改完聚簇索引上的记录X并提交,此时A事务需要在此读取记录X,按照定义,此时聚簇索引上的记录是不允许读取的,如何判定呢?也就依赖Read View机制了

Read View也称作一致性视图,其主要包含4个主要的内容:

  • m_ids:在生成Read View时,当前系统中活跃的读写事务的事务ID列表;
  • min_trx_id:在生成Read View时,当前系统中活跃的读写事务中最小的事务ID,即m_ids中的最小值;
  • max_trx_id:在生成Read View时,当前系统中活跃的读写事务中最大的事务ID,即系统应该分配给下一个事务的事务ID(全局事务ID的值);
  • creator_trx_id:在生成Read View时,当前事务的事务ID。

其中max_trx_id要注意下,并不一定是m_ids中的最大值,而是生成Read View时的全局事务ID值。因为事务ID时递增(循环)分配的,在RR隔离级别下,假设当前活跃的事务ID有1,2,3,事务ID=3的事务提交后,再开启一个事务A,发起读操作,此时Read View时m_ids=[1,2,4],min_trx_id=1,max_trx_id=4,如果有另一个写事务B提交了,消耗了一个事务ID=4,那么此时事务A进行写操作,就会出现creator_trx_id=5的情况。

为什么会这样呢?我们要明白事务ID的生成并不是开启事务(执行begin操作)时就确定的,而是第一次执行写操作时确定的
而Read View生成时机是在读操作前确定的,但RC与RR还不同,RC是每次读操作前都生成一个Read View(保证可以读已提交数据),而RR是在第一次读操作前生成一个Read View,就不会变动了(保证可重复读)

2.1、判定机制

MySQL根据Read View读要访问的记录依次进行以下判定,来决定是否可访问:

  1. 如果被访问记录的trx_id等于creator_trx_id相等,这意味当前事务在访问它自己修改的记录,允许被访问;
  2. 如果被访问记录的trx_id小于min_trx_id,这意味被访问记录在当前事务生成Read View时已经提交了,允许被访问;
  3. 如果被访问记录的trx_id大于等于max_trx_id,这意味被访问记录在当前事务生成Read View之后产生的,不允许被访问;
  4. 如果被访问记录的trx_id在m_ids中,说明在当前事务生成Read View时被访问记录所属的事务还是活跃的,不允许被访问;
  5. 如果被访问记录的trx_id不在m_ids中,说明在当前事务生成Read View时被访问记录所属的事务已经提交了,允许被访问;

以上的判定机制,是实现RC和RR的基础。

三、参考

1]:庖丁解InnoDB之Undo LOG
2]:正确的理解MySQL的MVCC及实现原理

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/76486.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

微服务中间件--微服务保护

微服务保护 微服务保护a.sentinelb.sentinel限流规则1) 流控模式1.a) 关联模式1.b) 链路模式 2) 流控效果2.a) 预热模式2.b) 排队等待 3) 热点参数限流 c.隔离和降级1) Feign整合Sentinel2) 线程隔离2.a) 线程隔离(舱壁模式) 3) 熔断降级3.a) 熔断策略-慢…

PSP - 开源可训练的蛋白质结构预测框架 OpenFold 的环境配置

欢迎关注我的CSDN:https://spike.blog.csdn.net/ 本文地址:https://spike.blog.csdn.net/article/details/132334671 Paper: OpenFold: Retraining AlphaFold2 yields new insights into its learning mechanisms and capacity for generalization Open…

提升管班小诀窍

在传统教育中,将考试结果告知家长一直是一项相对麻烦的任务。老师们不得不一个一个的打电话或发短信,耗费大量时间和精力。然而,现在有了易查分,老师们可以轻松地创建自己的成绩查询系统,大大简化了这项任务。 好消息&…

​Kubernetes的演变:从etcd到分布式SQL的过渡

DevRel领域专家Denis Magda表示,他偶然发现了一篇解释如何用PostgreSQL无缝替换etcd的文章。该文章指出,Kine项目作为外部etcd端点,可以将Kubernetes etcd请求转换为底层关系数据库的SQL查询。 受到这种方法的启发,Magda决定进一步…

AMBA总线协议(4)——AHB(二)

目录 一、前言 二、AHB操作概述 三、AHB 基本传输 1、简单传输 2、带有等待的传输 3、多重传输 四、AHB传输类型 五、小结 一、前言 在之前的文章中对于AMBA AHB做了一个简单的介绍,AHB 主要用于高性能模块(如 CPU、DMA 和 DSP 等)之间的连接&#x…

ChatGPT和Claude的能力全测评

创造性思维/语言 提示:“写一首 4 行诗,每行只有 3 个词,描写重庆” ChatGPT写诗👇 Claude写诗👇 仁者见仁,您怎么看谁更强? 提示: "如果你随机选择这个问题的答案,…

致敬,“编辑器之神”Vim的开发者Bram Moolenaar去世

编辑器之神Vim之父Bram Moolenaar逝世,享年62岁。其家人称,因过去几周里病情迅速恶化,Bram Moolenaar于8月3日去世。Bram的一生将大部分时间都奉献给了Vim,甚至在一个月前,他还在对Vim做着更新、修改工作。 Vim 是一个…

Air780EG —— 合宙4G定位解决方案

定位模式: 外部单片机控制模式(常见于AT固件客户): 开机 -> 搜星 -> 定位成功 -> 上报 -> 关机 780E自行控制模式(常见于二次开发客户,AT用户也可以使用): 开机 -> 搜星 -> 定位成功 -> 模块休眠,关闭GP…

css 文字排版-平铺

序: 1、表格的宽度要有!!!!! 2、容器不能是display:inline 3、扩展---》node全栈框架 代码 text-align-last: justify; width: 70px; display: inline-block; 主要是用于表单左侧文字排序!

毛利率下滑至负数,但小鹏汽车仍有信心

KlipC报道:8月18日周五,港股盘后美股盘前,小鹏汽车公布截至2023年6月30日的二季度业绩,据数据显示本季度小鹏营收50.6亿人民币,略超预期。但受G3i的存货减值及存货购买合约损失拖累,毛利率下滑至-3.9&#…

使用Xshell7控制多台服务同时安装ZK最新版集群服务

一: 环境准备: 主机名称 主机IP 节点 (集群内通讯端口|选举leader|cline端提供服务)端口 docker0 192.168.1.100 node-0 2888 | 3888 | 2181 docker1 192.168.1.101 node-1 2888 | 388…

Unity C# 引用池 ReferencePool

Unity C# 引用池 ReferencePool 1.目的 对于多次创建的数据使用new 关键字是十分消耗性能的,使用完成后由GC去自动释放,当一个类型的数据频繁创建可以使用引用池进行管理。 2.实现 项目目录 IReference 接口 要放入引用池的数据只需要继承这个接口…