【MySQL性能优化】- 一文了解MVCC机制

MySQL理解MVCC

😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🏆 博客首页   @怒放吧德德  To记录领地
🌝分享学习心得,欢迎指正,大家一起学习成长!
转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人

在这里插入图片描述

文章目录

  • MySQL理解MVCC
    • 简介
    • 理解MVCC
      • undo日志版本链
      • read-view机制
      • 版本链对比规则
    • 案例理解
      • 可重复读
        • 时刻6查询
        • 时刻9查询
        • 时刻13查询
        • 时刻14查询
      • 读已提交
        • 时刻9查询
        • 时刻13查询
    • 总结

转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人

简介

多版本并发控制(MVCC,Multi-Version Concurrency Control)是一种常用于数据库管理系统的并发控制方法,MySQL数据库中的InnoDB存储引擎就实现了这种技术。MVCC通过在每个事务中对数据进行版本控制来实现多个事务的高效并发执行,增强了数据库的读写性能,并且减少了锁的需求。

理解MVCC

在MySQL的可重复读的隔离级别中,同样的SQL查询语句在同一个事务中,查出来的数据是一致的,其他事务对这些数据进行修改,当前事务是不可见的。
这个隔离级别就是由MVCC机制来实现的。对一行数据并不会通过对读和写加互斥锁来保证隔离性,避免了频繁加锁互斥,而串行化隔离级别是通过读写互斥实现。

MySQL中读以提交和可重复读隔离级别都是通过MVCC。

undo日志版本链

undo日志版本链是指一行数据被多个事务依次修改后,为了保持数据修改之前版本的可访问性,InnoDB不会直接覆盖旧数据。会将数据的旧版本保存到undo日志中,并且用隐藏字段trx_id(事务id)和roll_pointer(回滚指针)将这些日志串联起来成为一组历史版本链。

这个undo日志不只是保存单个版本,而是随着时间推移和更多事务的执行,可能保存同一数据项的多个历史版本。这些历史版本形成一个链条,称为版本链。当需要某个记录的历史状态时,可以通过回滚undo日志中的操作来获取旧版本数据,或者在不同隔离级别的读取事务中适当地提供旧数据,以此来保证一致性读取。

如下图,可以很好的理解什么是undo日志版本链
在这里插入图片描述

如上图,我们在插入数据的时候,会开启事务,所以会带着一个事务id,接着对这条数据进行修改,MySQL也会将修改的数据加上事务id以及回滚指针(roll_pointer),并且由这个回滚指针来指向上一个事务的旧数据版本,这样就构成了日志版本链。

read-view机制

read-view机制是InnoDB存储引擎实现MVCC的一种来创建一致性读取视图的技术。主要作用是用来确保可重复读和读已提交的隔离级别下,事务能够读到一致的数据快照,即使其他事务在对数据进行修改。
当一个事务想要执行一致性读取操作时候,InnoDB通过多版本并发控制(MVCC)来保存数据的多个版本,每个版本都有一个唯一的事务ID(trx_id)与之关联。read-view机制就会创建一个视图,这个视图是由执行查询时所有未提交的事务id数组组成(数组最小的事务id为min_trx_id)和已创建事务最大id为max_trx_id组成,还有一个creator_trx_id,用来表示生成该read-view的事务ID。
在这里插入图片描述

以上图示read-view机制的区间。

版本链对比规则

1、如果trx_id<min_trx_id,表示生成该版本的事务在事务开始之前已经提交,则该版本对事务可见。
2、如果trx_id>max_trx_id,表示生成该版本的事务在事务开始后才开始,则该版本对事务不可见。
3、如果min_trx_id≤trx_id≤max_trx_id,则需要判断是否在视图数组trx_ids中。

  • 1)、如果trx_id在视图中,表示生成该版本是还没提交的事务,因此该版本对事务不可见。
  • 2)、如果trx_id不在视图中,表示生成该版本的事务是已提交的,因此该版本对事务可见。

对于删除的情况,会将版本链的最新数据复制一份,然后将trx_id修改成删除操作的trx_id,同时会在记录的头信息的标记位(delete_flag)上设置true,用来表示已经删除,在查询时,如果对应记录的delete_flag为true,则表示已经被删除,就不会返回数据。

案例理解

接下来我们通过一个案例来理解。(本次通过上篇文章所用到的数据表来作为案例)
我们假设有三个事务,根据时间顺序会执行不同操作(这里在如下的excel图中会有时刻来标记),以及提交的时间点不同,由此案例来了解MVCC机制是如何通过undo日志版本链和read-view机制工作的。并且介绍可重复读以及读已提交的MVCC机制。

可重复读

首先,假设我们插入一条新的数据(id=12)。然后我们有几个事务在执行各种操作,并且都有相应的事务id,具体的执行过程如下的excel图,用来明确表示各个事务在时间戳的执行流程。
在这里插入图片描述

注:这里需要注意一下,begin/start transation命令并不是一个事务的起点,具体真正开启事务是在执行到第一个修改操作InnoDB表的语句,这时候才会有事务id,MySQL内部是按照事务的启动顺序来分配事务id的。

时刻6查询

首先来看一种情况,事务id:100和101执行了更新操作,但是没提交,事务id:102对id=12进行了更新,并且提交事务,我们通过另一个会话进行查询id=12的这条记录,可见查出的first_name是102更新的数据。
在这里插入图片描述

我们来深入了解这MVCC机制,是如何从undo日志版本链中进行比对获取这个102所更新的数据。
如下图,首先我们需要知道read-view所选中的min_trx_id和max_trx_id。通过当前系统中活跃的最小事务id,从表格中可以看出min_trx_id是事务100,已创建事务最大id为max_trx_id是事务102,100,101是未提交的活跃事务。read-view:[100, 101], 102。

read-view {m_ids: [100, 101],   // 事务100和事务101均未提交min_trx_id: 100,     // 活跃未提交事务中最小的事务IDmax_trx_id: 102,     // 已创建事务最大事务的IDcreator_trx_id: 102  // 创建这个read-view的当前事务的ID
}

在这里插入图片描述

从日志版本链中看出事务102修改后会将回滚指针指向事务id为60上。然后就是进行版本链比对,当前row的trx_id=102,刚好是等于max_trx_id,接着需要判断这个102事务id是否在视图上,显然102是不在[100,101]中,所以就会认为这条数据是可见的,于是输出的值就是102这个事务的数据。

时刻9查询

我们接着往下走,事务id为100的事务执行了两次对id为12的记录进行更新,两次更新之后,事务还没提交,此时select 1会话又进行了一次查询。此时的查出来的数据依然是Liyongde,依旧是事务102更新的数据。
在这里插入图片描述

我们再来分析这个过程。此时如下图,read-view:[100,101], 102。
在这里插入图片描述

根据版本链,最新的数据是事务100更新的数据“Li2”,但是根据版本链规则判断,事务id=100属于视图数组里面,并且是没有提交的,于是就往版本链指向的版本进行判断,直到到达事务id=102的这条记录,不属于视图数组中,认为是可见的,因此返回的数据是“Liyongde”。

时刻13查询

接着看下一种情况,事务100提交了,随即事务101进行了一次更新,并且不提交,此时数据库的数据肯定是“Li2”,之后select 1进行查询id=12的记录,此时的read-view又是否会发生变化呢?得到的结果又是什么呢?
在这里插入图片描述

可见查出来的数据还是“Liyongde”,这是符合可重复读隔离级别的。还是需要通过undo日志版本链的规则来进行研究为什么得到的数据还是事务102提交的数据。
先确定视图数组,在可重复读级别下,同事务中的read-view是不会发生变化。所以依然是[100,101], 102。
在这里插入图片描述

此时数据库id=12是“Li2”,但是查出来的数据还是“Liyongde”,这是MVCC机制通过日志版本链的比对规则,从而达到可重复读的隔离机制。首先当前的trx_id=101,而101处于min_trx_id与max_trx_id之间,进一步判断是在视图里面,所以不可见,依此类推直到102不在视图中,则得到的记录是“Liyongde”。因为一致性视图在同事务并不会发生变化,因此,即便直到100,101,102三个事务全部都提交之后,Select 1查询得到的数据依旧是“Liyongde”。

注:在可重复读级别下,同事务中的read-view是不会发生变化。
这是因为可重复读的设计原则就是确保在同一个事务执行过程中,所看到的数据总是与事务在启动时看到的数据保持一致。当事务启动时,它会创建一个read-view,这个read-view在事务的整个生命周期内都是固定的,不会随着其他事务的提交或修改而改变。这样,即使在事务执行期间有其他事务修改了数据,当前事务所看到的数据仍然与启动时一致,从而保证了数据的可重复读性。因此,在可重复读的隔离级别下,同一个事务的read-view是不会变化的。

时刻14查询

如果此时有个新的事务Select 2,这个事务也是没有分配事务id,一直下来也没有执行查询操作,直到100,102都提交之后在执行了查询。那么此时的查询结果会是什么?
在这里插入图片描述

一致性视图(read-view)的状态取决于事务的启动时刻。根据excel图,我们可以知道创建的read-view数据以及日志版本链,如下图。
在这里插入图片描述

根据版本连的对比,可以得出此时事务查出的数据是“Li2”。当数据库事务开启之后的头一次查询,实际上read-view就已经创建了。我们通过以下例子来测试这个结果。
在这里插入图片描述

因为1是在修改之前进行了查询,此时就已经创建了一致性视图,接着进行修改值,哪怕已经提交了,查出来的结果依然是之前的数据;而2是在修改提交之后才进行的查询,此时创建的一致性视图就已经是更新过的事务数据。

读已提交

如上的案例,我们知道,在可重复读的隔离机制下,read-view是在开启事务的第一次查询就已经创建了,并且是直到事务的结束之前是不会发生变化。而接下来要介绍的读已提交隔离级别就有点不同,主要是read-view的创建,在读已提交的隔离级别下,read-view会在每次的查询的时候进行变化。

时刻9查询

根据上面的excel图,在时刻9的查询中,我们可以得出此时创建的read-view,事务102是提交的,事务100和101都是活跃未提交的事务,所以活跃数组则是[100, 101],当前事务为102,min_trx_id=100,max_trx_id=102。
接着就是一样的进行日志版本对比,对比规则与上文提到的方式是一致的,102不在视图中,所以数据可见,最后返回的是“Liyongde”。

时刻13查询

接着再来看看时刻13的情况,这个时候事务100也提交了,因为读已提交的read-view会在每次的查询发生变化,那么此时活跃事务就剩下了101,所以数组是[101],当前事务为102,min_trx_id=101,max_trx_id=102。
接着就是判断了,根据规则进行比对,最新的版本链中是事务id101,其是落在视图中,所以是不可见的数据,接着往上个版本看,事务id100是小于min_trx_id,因此此条数据是可见的。
在这里插入图片描述

总结

MVCC是一种用于解决数据库并发问题的乐观锁技术,多版本并发控制通过保存数据在某个时间点的快照来实现。换句话说,读操作不会阻塞写操作,写操作也不会阻塞读操作,以此来提高数据库性能。在每次对数据的操作,都用在undo日志版本链中进行。

👍创作不易,如有错误请指正,感谢观看!记得点赞哦!👍

转发请携带作者信息 @怒放吧德德 @一个有梦有戏的人

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

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

相关文章

【Qt】QListView 显示富文本,设置文本内容颜色

【Qt】QListView 显示富文本&#xff0c;设置文本内容颜色 文章目录 I - 控件使用II - 显示富文本III - 注意事项 I - 控件使用 Qt 的 MVC 架构为 MV &#xff0c;Controller 部分继承到了 View 里&#xff0c;View(视图) 设置 Model(模型)&#xff0c;Model 设置数据 这里使用…

工作中Git如何切换远程仓库地址

工作中Git如何切换远程仓库地址 部门之前的仓库不用了&#xff0c;重新建了一个仓库&#xff0c;但是上传代码还是上传到了之前的仓库里面了&#xff0c;所以得进行修改&#xff0c;下面将修改地址的方法进行操作。 方法一、直接修改远程仓库地址 查看当前远程仓库地址 git …

ideaSSM校医院管理网页模式开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 idea ssm 校医院管理系统是一套完善的完整信息管理系统&#xff0c;结合SSM框架完成本系统SpringMVC spring mybatis &#xff0c;对理解JSP java编程开发语言有帮助系统采用SSM框架&#xff08;MVC模式开发&#xff09;&#xff0c; 系统具有完整的源代码和数据…

前端跨页面通信的几种方式---同源

参考链接 1、LocalStorage:当 LocalStorage 变化时&#xff0c;会触发storage事件。利用这个特性&#xff0c;我们可以在发送消息时&#xff0c;把消息写入到某个 LocalStorage 中&#xff1b;然后在各个页面内&#xff0c;通过监听storage事件即可收到通知。 2、BroadCast C…

Java实现知乎热点小时榜爬虫

1.效果演示 1.1 热点问题列表 启动程序后&#xff0c;自动展示热点问题&#xff0c;并等待终端输入 1.2 根据序号选择想看的热点问题 输入问题序号&#xff0c;展示回答内容 1.3 退出 输入q即可退出程序 2.源码 2.1 pom.xml <?xml version"1.0" enco…

java数据结构与算法刷题-----LeetCode46. 全排列

java数据结构与算法刷题目录&#xff08;剑指Offer、LeetCode、ACM&#xff09;-----主目录-----持续更新(进不去说明我没写完)&#xff1a;https://blog.csdn.net/grd_java/article/details/123063846 文章目录 1. 暴力回溯2. 分区法回溯 1. 暴力回溯 解题思路&#xff1a;时…

【软考高项】六、信息技术发展之计算机网络知识点

1、网络作用划分 个人局域网(PAN)、局域网(LAN)、城域网(MAN)、广域网(WAN)、公用网、专用网。 2、OSI七层 物理层、数据链路层、网络层、传输层、会话层、表示层、应用层 3、广域网协议类型 PPP点对点协议、ISDN综合业务数字网、xDSL(DSL数字用户线路的统称:HDSL.SDSL、M…

04- 基于SpringAMQP封装RabbitMQ,消息队列的Work模型和发布订阅模型

SpringAMQP 概述 使用RabbitMQ原生API在代码中设置连接MQ的参数比较繁琐,我们更希望把连接参数写在yml文件中来简化开发 SpringAMQP是基于AMQP协议定义的一套API规范,将RabbitMQ封装成一套模板用来发送和接收消息 AMQP(Advanced Message Queuing Portocol)是用于在应用程序…

[CISCN2019 华东南赛区]Web11

模块注入题&#xff0c;这类题一般拥有固定的payload。 界面大概就是这么个样子 返回了IP地址&#xff0c;提示getip&#xff0c;xff等。 这是smarty模板。很明显了&#xff0c;这个模板存在xff处的命令执行。抓取数据包并添加字段 X-Forwarded-For:{{system(ls)}} cat /fla…

密码学——MAC

消息认证码 在信息发送和接收过程中,若攻击者能够得到信息,进行篡改,就能达到欺骗,诈骗,冒名顶替的作用。为了防止冒名诈骗,一个对策就是使用消息认证码——MAC: Message Authentication Code。 消息认证码,即确定消息真实性的认证程序。发件人将想要发送的信息和从哪个…

【视觉三维重建】【论文笔记】Deblurring 3D Gaussian Splatting

去模糊的3D高斯泼溅&#xff0c;看Demo比3D高斯更加精细&#xff0c;对场景物体细节的还原度更高&#xff0c;[官网]&#xff08;https://benhenryl.github.io/Deblurring-3D-Gaussian-Splatting/&#xff09; 背景技术 Volumetric rendering-based nerual fields&#xff1a…

linux sshd_config配置说明

[root01 ssh]# cat sshd_config #######################SSH Base Config################## #######通过OpenSSH工具入xshell连接默认端口 可以改成其他默认是22 PAM 认证过程 1&#xff09;使用者执行/usr/bin/passwd程序&#xff0c;并输入密码。 2&#xff09;passwd开…

【开源-土拨鼠充电系统】鸿蒙 HarmonyOS 4.0+微信小程序+云平台

本人自己开发的开源项目&#xff1a;土拨鼠充电系统 ✍GitHub开源项目地址&#x1f449;&#xff1a;https://github.com/cheinlu/groundhog-charging-system ✍Gitee开源项目地址&#x1f449;&#xff1a;https://gitee.com/cheinlu/groundhog-charging-system ✨踩坑不易&am…

192基于matlab的雷达信号进行RD图的仿真

基于matlab的雷达信号进行RD图的仿真&#xff0c;在距离进行匹配滤波&#xff0c;具体方法是与回波信号的FFT与参考信号对称共轭的FFT相乘&#xff0c;再IFFT。在多普勒维通过多普勒滤波器组进行滤波&#xff0c;相当于进行FFT。程序已调通&#xff0c;可直接运行。 192 matlab…

Elasticsearch:使用标记修剪提高文本扩展性能

作者&#xff1a;来自 Elastic Kathleen DeRusso 本博客讨论了 ELSER 性能的令人兴奋的新增强功能&#xff0c;该增强功能即将在 Elasticsearch 的下一版本中推出&#xff01; 标记&#xff08;token&#xff09;修剪背后的策略 我们已经详细讨论了 Elasticsearch 中的词汇和…

Landsat、哨兵等免费数据下载地址汇总

我们科研和一些工程化应用中&#xff0c;经常会用到免费的Landsat、哨兵1/2/3等数据。下面介绍常用的下载网址&#xff1a; 1.哨兵系列数据 哨兵系列数据在https://scihub.copernicus.eu/dhus 上简单注册一个用户就可以下载&#xff0c;就是速度慢点&#xff0c;还限制一个用…

Linux第77步_处理Linux并发的相关函数

了解linux中的“原子整形数据”操作、“原子位数据”操作、自旋锁、读写锁、顺序锁、信号量和互斥体&#xff0c;以及相关函数。 并发就是多个“用户”同时访问同一个共享资源。如&#xff1a;多个线程同时要求读写同一个EEPROM芯片&#xff0c;这个EEPROM就是共享资源&#x…

【数学建模】线性规划

针对未来可能的数学建模比赛内容&#xff0c;我对学习的内容做了一些调整&#xff0c;所以先跳过灰色关联分析和模糊综合评价的代码&#xff0c;今天先来了解一下运筹规划类——线性规划模型。 背景&#xff1a; 某数学建模游戏有三种题型&#xff0c;分别是A&#xff0c;B&am…

远程办公、企业内网服务器的Code-Server上如何配置使用CodeGeeX插件

很多小伙伴都会在工作中使用code-server&#xff0c;比如说远程办公&#xff0c;当你需要在家访问你的工作环境&#xff0c;亦或者是你们公司的Docker是放入服务器中。code-server 无疑是最好的选择&#xff0c;它可以让你通过互联网安全地连接到远程服务器上的开发环境并且使用…

【保姆级】GPT的Oops问题快速解决方案

GPT的"Oops"问题通常指的是GPT在处理请求时突然遇到错误或无法提供预期输出的情况。要快速解决这个问题&#xff0c;可以尝试以下分步策略&#xff1a; 确认问题范围&#xff1a; 首先&#xff0c;确认问题是偶发的还是持续存在的。如果是偶发的&#xff0c;可能是临…