MySQL InnoDB MVCC数据结构分析

1、概述

MVCCMultiversion Concurrency Control)多版本并发控制,通过维护不同的版本号,提供一种很好的并发控制技术,这种技术能够使读写操作不冲突提升并发性能

MySQL InnoDB存储引擎,在更新某些数据时,并非使用新数据覆盖旧数据,而是标记旧数据是过时的,同时在其他地方新增一个数据版本。因此,同一份数据有多个版本存储,但只有一个是最新的

根据事务的ACID特性:原子性,一致性,隔离性,持久性MVCC主要解决的是隔离性问题。

特性

解释

Atomicity 原子性

事务的所有行为或者全部提交或者全部不做

Consistency 一致性

事务在完成时使得整个数据库仍保持一致性状态

Isolation 隔离性

并发的事务看不到彼此正在进行的更新操作

Durability 持久性

一个成功提交的事务对数据库的更新是永久的

      并且InnoDB存储引擎采用Next-Key Loking的算法来避免幻读现象。在事务隔离界别Read CommitedRepeatable Read下,InnoDB存储引擎使用非锁定的一致性读。

2、隐藏列

      InnoDB表中会存有三个隐藏字段,这三个字段是mysql默认帮我们添加的。

      MySQL 5.7.29版本 dict文件夹下dict0dict.cc文件的实现源码中,从dict_table_add_system_columns()函数可以看到其内部实现:

分析:

      从函数中可以看到当满足一定的条件时,若建表时没有指定主键,InnoDB会使用该ROW_ID创建一个聚簇索引,MySQL会自动生成一个隐藏的自增ID;事务的ID和回滚指针也被生成,用于记录修改(insert/update/delete)该记录的事务ID和指向这条记录的上一个版本。

      当产生新的版本,旧的版本将被放到undo log中,并且当前记录的回滚指针指向上一个版本的地址。

当建表没有指定主键或新开一个事务对该行数据有修改操作时,会增加隐藏列,隐藏列的产生会调用一个函数,在dict文件夹下dict0dict.cc文件中的dict_table_add_system_columns()函数中,具体定义了这三个隐藏列:

隐藏字段名称

意义

大小

ROW_ID

隐藏的自增ID,当建表没有指定主键,InnoDB会使用该ROW_ID创建一个聚簇索引。

6 byte

DB_TRX_ID

最近修改(更新/删除/插入)该记录的事务ID。

7 byte

DB_ROLL_PTR

回滚指针,指向这条记录的上一个版本。

6 byte

MVCC 使用了三个字段来实现版本并发控制。分别为事务字段,回滚指针字段,是否删除字段。

对于删除标记位的解读:

字段名称

意义

DEL_BIT

判断该行记录是否已经被删除。

分析:

      删除标记位是MVCC在进行删除操作时,对该条记录的删除位状态进行标记,当DEL_BITtrue时,表示已经删除,但未真删除,若需要回滚,可根据状态位进行逆向操作,insert回去,这样保证了在勿删等操作下对于数据的找回

3undo log &版本链

      undo log被称为回滚日志,它是用于记录数据被修改前的信息undo log主要记录的是数据的逻辑变化,为了在发生错误时回滚之前的操作,需要将之前的操作都记录下来,然后在发生错误时才可以回滚。

      数据库事务未提交时,会将事务修改数据的镜像(即修改前的旧版本)存放到undo日志里,当事务回滚时,或者数据库奔溃时,可以利用undo日志,即旧版本数据,撤销未提交事务对数据库产生的影响。

每次写入数据或者修改数据之前都会把修改前的信息记录到undo log

undo log 有什么作用?

  undo log 记录事务修改之前版本的数据信息,因此假如由于系统错误或者rollback操作而回滚的话可以根据undo log的信息来进行回滚到没被修改前的状态。

  undo log是用来回滚数据的,用于保障未提交事务不会对数据库的ACID特性产生影响

undo log 工作步骤

      1).开始事务

      2).记录数据行数据快照到undo log

      3).更新数据(此时在缓存中操作)

      4).undo log写到磁盘

      5).将数据写到磁盘

      6).提交事务

结论:

      (1)、每条数据变更(insert/update/delete)操作都伴随一条undo log的生成,并且回滚日志必须先于数据持久化到磁盘上

      (2)、所谓的回滚就是根据回滚日志做逆向操作,比如delete的逆向操作为insertinsert的逆向操作为deleteupdate的逆向为update等。

      undo log中,当保存的版本多起来后,就会形成一条链表,这就是版本链,它表示当前最新记录数据与旧数据之间的关系。通过undo log与当前最新数据形成的版本链,可以找到任一版本的数据。如下图,模拟三个不同id的事务先后执行一些操作后,select1时形成的版本链。

undo log 回滚日志中,事务在insert新记录产生的insert undo log,当事务提交之后可以直接丢弃;事务在进行 update 或者 delete 的时候产生的update undo log,在快照读的时候还是需要的,所以不能直接删除,只有当系统没有比这个log更早的read-view了的时候才能删除。

      定期唤醒purge线程管理比现在最早的活动事务还早的undo log 遍历undo日志,构造索引记录,查找并删除。

功能: 回收局促索引/二级索引上的删除项。不足:为了能够删除二级索引记录,undo中必须记录完整索引项

ps:所以长事务会产生很多老的视图导致undo log无法删除 大量占用存储空间。

4ReadView可见性

read view: 一致性视图,是MySQL秒级创建视图的必要条件,比如一个事务在进行简单的select 操作(快照读)的时候会创建一个 read view 读取的只是当前事务的可见版本不用加锁

通过跟踪mysql源码,可以在判断该条记录可见性,总会涉及到一个非常重要的类ReadViewRead View是事务开启时当前所有事务的一个集合,这个类中存储了当前Read View最大事务ID最小事务IDReadView类保存在include文件夹下read0types.h头文件中,从源码中可以看到ReadView类中私有成员变量的定义信息:

…….

可以看到read0types.h头文件中ReadView类中定义的私有成员变量,下面对它各个字段进行解读:

ReadView类的成员变量

意义

trx_id_t m_low_limit_id

读取的内容应该看不到trx id> =此值的任何事务。 相当于max_id。

trx_id_t m_up_limit_id

读取结果应查看所有严格 < 此值的trx id。 相当于min_id。

trx_id_t m_creator_trx_id

创建当前视图的事务id。相当于alive_id。

ids_t      m_ids

当前活跃事务(即未提交的事务)的数量。

node_t     m_view_list

事务系统中的一致性视图链表

......

......

分析:

      因为逆序排列,所以不要对于命名中的lowup字样有单纯字面上的理解!

      m_low_limit_id意思,根据源码注释以及上下文的解读,此值的意义为能看到当前行版本的高水位标识,>= low_limit_id皆不能看见;

      m_up_limit_id的意思为能看到当前行版本的低水位标识,< m_up_limit_id皆能看见;

      在可见性的算法上,最核心的算法被封装成一个函数changesvisible(),它是判断可见性算法的核心,根据查询的ReadView即可判断可以看见哪个版本的数据。changesvisible()函数作为成员函数被封装在include文件夹下read0types.h头文件的ReadView类中,可见其重要性,它能够对不同隔离界别下的ReadView的判断。

分析:

从第一个if分支可以看到,如果ID小于Read View中最小的, 则这条记录是可以看到,即id<= m_up_limit_id。说明这条记录是在select这个事务开始之前就结束的;

从第二个if分支可以看到,如果比Read View中最大的还要大,则说明这条记录是在事务开始之后进行修改的,所以此条记录不应查看到;

ifelse if分支中,判断是否在Read View中, 如果在说明在创建Read View 此条记录还处于活跃状态则不应该查询到,否则说明创建Read View是此条记录已经是不活跃状态则可以查询到。

画出该程序的流程图,对于该函数对于可见性的算法一目了然。

对于不可见的记录都是通过row_vers_build_for_consistent_read()函数查询undo构建的老版本记录,直到记录可见。这个函数在row文件夹下row0sel.cc文件中可以看到,省略不重要的代码,可以看到这个循环只有在符合可见性的条件才会break,如果不符合就会回溯到上一个版本:

MVCC类中,其实也会有一个链表,这个链表将每次生成的ReadView对象建立联系,形成一个ReadView链。

include文件夹下read0read.h头文件中,对MVCC类进行了定义,并且在最后定义了一个ReadView链的成员变量,将生成的ReadView链接起来。

……

进一步查看链表的结构,可以看到链表中只有三个变量,分别链表中节点的个数、头指针和尾指针。

5、隔离性与可见性

不同的事务隔离级别,可见性的实现也不一样。但是在InnoDB存储引擎中,MVCC只能在RC或者RR隔离级别下使用。通过对不同隔离级别下的产生的ReadView研究,可以发现两种隔离级别下ReadView的产生是不同的。

隔离级别

可见性比较规则

Read Commited

事务内的每个查询语句都会重新创建Read View,这样就会产生不可重复读现象发生。

Repeatable Read

事务内开始时创建Read View , 在事务结束这段时间内 每一次查询都不会重新重建Read View , 从而实现了可重复读。

可以这样理解,再RR隔离级别下,事务开始后只在第一次创建后才会生成每次进行,不管中间有多少的操作语句,之后就不会再生成新的的ReadView了;

RC隔离级别下,事务开始后,创建ReadView,不仅如此,之后的查询语句都会产生新的ReadView,这样就会出现不能读取重复数据的问题。

6、总结

1)、实现了非阻塞的读操作(OLTP应用),写操作也只锁定必要的行,是个行级锁 select不会加锁,读和写操作性能好,提高了数据库的并发处理能力;缺点:需要额外的存储空间

2)、innodbmvcc是每次事务都有递增的版本号,通过在每行记录的后面添加隐藏字段,存储操作它事务的版本号,实现MVCC;(在底层的是使用事务id、回滚指针、undo log和可见性算法实现的)

3)、undo log将各个版本的数据形成一个版本链,通过可见性比较规则来查询相应版本的数据;

4)、通过保存数据在某个时间点的快照实现的,也就是一致性视图read view);

5)、mvcc只在RRRC两个隔离级别下工作;用户可以查看当前数据的前一个或者前几个历史版本。保证了ACID中的I-隔离性。

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

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

相关文章

Colorful/七彩虹将星X17 XS 22 Win11原厂OEM系统 带COLORFUL一键还原

安装完毕自带原厂驱动和预装软件以及一键恢复功能&#xff0c;自动重建COLORFUL RECOVERY功能&#xff0c;恢复到新机开箱状态。 【格式】&#xff1a;iso 【系统类型】&#xff1a;Windows11 原厂系统下载网址&#xff1a;http://www.bioxt.cn 注意&#xff1a;安装系统会…

设计模式、系统设计 record part02

软件设计模式&#xff1a; 1.应对重复发生的问题 2.解决方案 3.可以反复使用 1.本质是面向对象 2.优点很多 1.创建型-创建和使用分离 2.结构型-组合 3.行为型-协作 571123种模式 UML-统一建模语言-Unified Modeling Language 1.可视化&#xff0c;图形化 2.各种图&#xff08;9…

服务器操作系统【sar 命令】

sar 安装、语法参数说明以及示例 文章目录 功能概述一、功能介绍1.安装配置2. 配置3. 启动二、sar 语法及参数说明三、示例及释义1.汇报 io 传输速率信息2.内存分页信息3.块设备状态信息4.hugepages 利用率统计信息5.列长度和负载平均值6.内存利用率统计信息7.swap 交换空间利用…

ARM点灯---看手册

知识点&#xff1a; 一个程序可能会遇到内存泄漏问题&#xff0c;可能一次运行泄漏几M大小&#xff0c;执行几个小时才会泄漏到站崩溃&#xff0c;所以要查看是否有内存泄漏。 查看手册教程 0927-上午 视频1&#xff1a;25&#xff1b;00 硬件程序开发流程 最小系统:单片…

16.第二阶段x86游戏实战2-发包函数和怎么去找改写过的发包函数

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 本次游戏没法给 内容参考于&#xff1a;微尘网络安全 本人写的内容纯属胡编乱造&#xff0c;全都是合成造假&#xff0c;仅仅只是为了娱乐&#xff0c;请不要…

使用celery+Redis+flask-mail发送邮箱验证码

Celery是一个分布式任务队列&#xff0c;它可以让你异步处理任务&#xff0c;例如发送邮件、图片处理、数据分析等。 在项目中和celery 有关系的文件如下&#xff1a; task.py : 创建celery.py 对象&#xff0c;并且添加任务&#xff0c;和app绑定&#xff0c;注意&#xff1…

实习前学一学git

工作区 暂存区 本地仓库 远程仓库 git commit -m "提交信息" 提交的是暂存区里的内容&#xff0c;没有git add 的不会被提交到本地仓库

对抗攻击方法详解:梯度攻击、转移攻击与模型集成攻击

对抗攻击方法详解&#xff1a;梯度攻击、转移攻击与模型集成攻击 近年来&#xff0c;随着深度学习模型在各个领域取得惊人突破&#xff0c;对抗攻击&#xff08;Adversarial Attack&#xff09; 逐渐成为研究热点。对抗攻击旨在通过在输入数据上施加精心设计的微小扰动&#x…

这样做快速除甲醛入住新家 科学分解甲醛的产品哪个好

这样做快速除甲醛入住新家 科学分解甲醛的产品哪个好 在新房装修的喜悦之余&#xff0c;业主们不得不面对一个常见却又棘手的问题——甲醛污染。甲醛&#xff0c;这种无形的敌人&#xff0c;以其难以察觉的存在&#xff0c;对家人和孩子的健康造成潜在威胁。很多业主们在装修期…

ArcEngine C#二次开发图层处理:根据属性分割图层(Split)

需求&#xff1a;仅根据某一属性&#xff0c;分割图层&#xff0c;并以属性值命名图层名称保存。 众所周知&#xff0c;ArcGIS ArcToolbox中通过Split可以实现图形分割一个图层&#xff0c;以属性值命名图层&#xff0c;如下图所示。 本文仅仅依据属性值&#xff0c;将一个shp…

InfiniiVision 3000T X 系列示波器

InfiniiVision 3000T X 系列示波器 综述 3000T X 系列示波器外形更为小巧&#xff0c;并配有简明直观的触摸屏用户界面&#xff0c;为您带来高端测量技术。 凭借其出色的波形捕获率&#xff0c;您可以捕获在其他示波器上无法捕获的偶发毛刺和异常。 3000T X 系列示波器搭配了…

猫头虎带你解决:error Error: certificate has expired

&#x1f42f;猫头虎带你解决&#xff1a;error Error: certificate has expired &#x1f4a5; 今天有粉丝问猫哥&#xff1a;“&#x1f42f;猫头虎&#xff0c;我在 Node.js 项目中使用 Yarn 安装包时遇到了一个错误&#xff1a;Error: certificate has expired。你能帮忙解…

Android Studio 真机USB调试运行频繁掉线问题

一、遇到问题 Android Studio使用手机运行项目时&#xff0c;总是频繁掉线&#xff0c;连接很不稳定&#xff0c;动不动就消失&#xff0c;基本上无法使用 二、问题出现原因 1、硬件问题&#xff1a;数据线 换条数据线试试&#xff0c;如果可以&#xff0c;那就是数据线的…

TortoiseGit 下载和安装

下载 1&#xff0c;下载路径 Download – TortoiseGit – Windows Shell Interface to Git 2&#xff0c;选择windows64的&#xff0c; 3&#xff0c;下载完成后 安装 1&#xff0c;双击运行&#xff0c;点击next 2&#xff0c;点击next 3&#xff0c;点击next 4&#xff0…

后端回写前端日期格式化

问题 不进行格式化处理&#xff0c;就会导致传递的字符串很奇怪 解决方案 注解&#xff08;字段&#xff09; <dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.2</…

【大数据】大数据运维方案浅析总结

1. 引言 在大数据时代&#xff0c;如何高效管理和维护大规模数据平台&#xff0c;成为许多企业面临的重要挑战。本文将对市面上一些流行的大数据运维管理方案进行全面分析&#xff0c;包括Cloudera的CDH和CDP、Hortonworks的HDP、Apache的Ambari、国产开源平台Datasophon&#…

cups-browsed远程代码执行漏洞安全风险通告

今日&#xff0c;亚信安全CERT监控到安全社区研究人员发布安全通告&#xff0c;披露了cups-browsed 远程代码执行漏洞(CVE-2024-47176)。由于cups-browsed 服务在处理网络打印任务时&#xff0c;会绑定到 UDP 端口 631 上的 INADDR_ANY 地址&#xff0c;从而信任来自任何来源的…

什么是原生IP?

代理IP的各个类型称呼有很多&#xff0c;且它们在网络使用和隐私保护方面扮演着不同的角色。今天将探讨什么是原生IP以及原生IP和住宅IP之间的区别&#xff0c;帮助大家更好地理解这两者的概念和实际应用&#xff0c;并选择适合自己的IP类型。 一、什么是原生IP&#xff1f; 原…

【Java异常】(简简单单拿捏)

【Java异常】&#xff08;简简单单拿捏&#xff09; 1. 异常的简单介绍2. 异常的抛出2.1 语法 3. 异常的处理3.1 异常声明throws3.2 try-catch捕获并处理 4. 例子&#xff08;try-catch自定义异常&#xff09; 1. 异常的简单介绍 程序员在运行代码时会遇到很多异常&#xff0c…

Go语言开发后台框架不能只有CRUD还需有算法集成基础功能-GoFly框架集成了自然语言处理(NLP)分词、关键词提取和情感分析

前言 Go语言开发框架&#xff0c;我们要把Go的优势体现在框架中&#xff0c;不仅CRUD常规操作&#xff0c;还要把常用即有算力自己集成到框架中&#xff0c;而不是去购买第三方提供服务接口。作为开发者可以拓宽自己代码面&#xff0c;获取更多成就感&#xff0c;同时也提供自…