【MySQL】InnoDB存储引擎详解

InnoDB引擎是MySQL5.5版本之后默认的存储引擎

逻辑存储结构

首先是表空间Tablespace(ibd文件):一个mysql实力可以对应多个表空间,用于存储及记录,索引等数据

这些存储记录,索引等数据中是用(Segment)来存储的
段分为

  1. 数据段(Leaf node segment)
  2. 索引段(Non-leaf node segment)
  3. 回滚段(Rollback segment)

InnoDB是索引组织表,数据段就是B+树的叶子节点,索引段即为B+树的非叶子节点

段用来管理多个区(Extent)

区:表空间的单元结构,每个区为1MB,默认情况下,InnoDB存储引擎页的大小是16KB,即一个区中又64个页(Page)

页:是InnoDB存储引擎磁盘管理的最小单元,每个页的大小默认是16KB,为了保证页的连续性,InnoDB存储引擎每次从磁盘申请4-5个区

页中存放的是行Row,InnoDB存储引擎数据是按行进行存放的

如表中的隐藏字段:
Trx_id:每次对某条记录进行改动时,都会把对应的十五id赋值给trx_id隐藏列
Roll_pointer:每次对某条印记路进行改动时,都会把旧的版本写入到undo日志中,然后这个隐藏列相当于一个指针,同故宫他来找到该记录修改前的信息

架构

InnoDB引擎是MySQL5.5版本之后默认的存储引擎,他擅长事务处理,具有崩溃恢复特性,在日常中使用非常广泛

首先介绍InnoDB的内存结构

InnoDB内存结构

Buffer Pool:

缓冲池时主内存的区域,里面可以缓存磁盘上经常操作的真实区域,在执行CRUD操作时,前操作缓存池中的数据(如果没有,那么久从磁盘上加载并且缓存),然后再以一定频率刷新到磁盘,从而减少磁盘IO,加快处理速度

这么做的原因是,如果每次都是磁盘操作,那么就会出现大量的磁盘IO,而且是随机IO,这样非常消耗性能

缓冲池以Page页为单位,底层采用链表数据结构管理Page,根据状态,将Page分为三种类型

  1. free page:空闲page ,未被使用过
  2. clean page:被使用过,但是数据没修改
  3. dirty page:脏页,被使用过page,数据被修改过,与磁盘内的数据不一致

Change Buffer:

更改缓冲区(针对于非唯一二级缓存页),5.x的版本是一个叫Insert Buffer的东西,8.0才出现的

再执行DML语句时,如果这些数据Page没有在Buffer Pool中,不会直接操作磁盘,而会将数据变更存在更改缓冲区Change Buffer中,在未来数据被读取时,再将数据合并恢复到缓冲池中,再将合并后的数据刷到磁盘上

Change Buffer的意义
与聚集索引不同,二级索引通常是非唯一的,并且相对随机的顺序插入二级索引,同样,删除和更新可能会影响所引述中不相邻的二级索引页,如果每一次都操作磁盘,会造成大量的磁盘IO,有了ChangeBuffer之后,我们在缓冲池中进行合并处理,减少IO

Adaptive Hash Index:

自适应Hash索引,用于优化对Buffer Pool数据的查询,InnoDB存储引擎会监控对表上各索引的插叙,如果换查到hash索引可以提升速度,则建立hash索引,称为自适应hash索引

自适应哈希索引无需人工干预,是系统根据情况自动完成

Log Buffer

日志缓冲区,用来保存要写入到磁盘中的log日志数据(redo log,undo log),默认大小为16MB,日志缓冲区的日知会定期刷新到磁盘中,如果需要更新,插入或删除许多行的事务,增加日志缓冲区的大小可以节省磁盘IO;
可以配置缓冲区大小和日志刷新到磁盘的时机

磁盘结构

InnoDB磁盘结构

System Tablespace:

系统表空间是更改缓冲区的存储区域,如果是在系统表空间而不是每个表文件或通用表文件创建的,他也可能包含表和索引数据,(在5.X版本中还包含InnoDB数据词典,undolog等)

File-Per-Table Tablespaces:

每个表的文件表空间包含单个InnoDB表的数据和索引,兵存储在文件系统上的单个数据文件中

General Tablespace:

通用表空间,是手动创建的而不是系统自带的,需要通过CREATE TABLESPACE语法创建通用表空间,在创建时,可以指定该表空间
如:

# 创建一个通用表空间ts_xx, 这个表空间对应的磁盘文件xxx.ibd
create tablespace ts_xx add datafile 'xxx.ibd' engine = innodb;# 创建一个表xxx,他的表空间是上面创建的ts_xx
create table xxx(id long primary key auto_increment , name varchar(20)) engine = innodb tablespace ts_xx;

Undo Tablespaces

撤销表空间,MySQL实例在初始化时会自动创建两个默认的undo表空间(初始大小16M),用于存储undo log日志

Temporary Tablespaces

InnoDB使用绘画临时表空间和全局临时表空间,存储用户创建的临时表等数据

Doublewrite Buffer Files:

双写缓冲区,innoDB引擎将数据页从Buffer Pool刷新到磁盘前,先将数据页写入双鞋缓冲区文件中,便于系统异常时恢复数据

Redo Log:

重做日志,是用来实现事务的持久性,该日志文件由两部分组成:重做日志缓冲(redo log buffer) 以及重做日志文件(redo log),前者时在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都会存到该日志中,用于在刷新脏页到磁盘时,发生错误后进行数据回复
事务持久性依赖于该日志

分别介绍了内存和磁盘结构,那么就需要把两个结构连接起来,而后台线程就是把他们连接起来的工具

后台线程

后台线程的作用就是把InnoDB存储引擎缓冲池的数据在合适的时间刷新到磁盘文件中

后台线程分为四种

1. Master Thread:

核心后台线程,负责调度其他线程,还负责将缓冲池中的数据异步刷新到磁盘中,保持数据的一致性,还包括脏页的刷新,合并插入缓存,undo页的回收

2. IO Thread:

在InnoDB存储引擎中大量使用了AIO(异步非阻塞)来处理IO请求,这样可以极大地提高数据库的性能,而IO Thread主要负责这些IO请求的回调

IO Thread又包括四种

  1. Read Thread: 负责读操作,默认4个
  2. Write Thread:负责写操作,页默认4个
  3. Log Thread:负责将日志缓冲区刷新到磁盘,默认1个
  4. Insert Buffer Thread:负责将缓冲区内容刷新到磁盘,默认1个

下面是如何查看状态

show engine innodb status;

然后直接去找FILE I/O就可以看到IO线程了

3. Purge Thread

主要用于回收事务已经提交了的undo log ,在十五提交之后,undo log 可能不用了,就用它来回收

4. Page Cleaner Thread

协助 Master Thread 刷新脏页到磁盘的线程,可以减轻MT的工作压力,减少阻塞

InnoDB事务的原理

InnoDB引擎很重要的一个功能就是支持了事务

事务:是一组操作的集合,他是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,及这些操作要么同时成功,要么同时失败

事务的四大特性:ACID

原子性(Atomicity): 事务时不可分割的最小单元,同时成功或同时失败

一致性(Consistency): 事务完成时,必须使所有的数据都保持一致状态

隔离性(Isolation): 数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行

持久性(Durability): 事务一旦提交或回滚,他对数据库中的数据改变就是永久的

隔离性又涉及到了隔离级别:读未提交,读已提交,可重复读,串行化,默认可重复读

事务的原理

对于原子性,一致性,持久性来说,在InnoDB中是由redo log 和 undo log来保证的
隔离性是由锁机制和MVCC(多版本并发控制)来保证的

redo log保证持久性

redo log :重做日志记录的事务提交时数据页的物理修改,使用来实现事务的持久性的
该日志文件由两部分组成:重做日志缓冲(redo log buffer),以及重做日志文件(redo log),前者是在内存中,后者在磁盘中
当事务提交之后会把所有修改信息都存到日志文件中,用于刷新脏页到磁盘,发生错误时,进行数据恢复使用

过程
当事务的请求发送给数据库时,首先会看看内存的缓冲池有没有相对的数据,没有的话要去磁盘里面读出来加载到缓存中
在这里插入图片描述
当缓存池中,页的数据被进行了更改,就会形成脏页,会在下次对磁盘进行读写的时候给更改进去
脏页数据写回
但如果,脏页的数据刷新到磁盘的过程出错了,此时内存数据没刷新进去,但是事务已经提交了,这时候 - 由于磁盘数据与事务的数据不同,那么持久性就没得到保证

为了保证事务一致性,就出现了redo log,与刚才的直接提交的操作不同,他会先把脏页给到内存中的Redolog Buffer一份
Redolog Buffer中记录数据页变化
当客户端事务提交之后,RedologBuffer会向磁盘内提交数据页变化,持久性的保持在磁盘文件中

直接刷新到磁盘log

在这之后,如果脏页刷新到磁盘文件失败的话,他可以通过redo log来进行恢复

事务提交时直接刷新ibd和直接redolog记录这个过程看似相同,但其实有很大的差别:
在事务中,我们的操作大多都是随机操作各个数据页的,这其中涉及到了大量的随即磁盘IO,很耗费性能,而log日志时顺序记录的,即顺序磁盘IO,这两者之间相差了很大的性能
这种机制叫做WAL(Write-Ahead Logging)

因为脏页早晚都会正常写入,所以log里就会有很多无用的日志,这时候就需要定时清理,两个log文件循环记录

Undo Log 解决事务原子性

undo log:回滚日志,用于记录数据被修改前的信息,作用有两个:提供回滚和MVCC

undolog 和redolog记录物理日志不一样,他记录的是逻辑日志
比如我写了一条delete,删除id为1的数据,那么undolog记录的则是相反的,插入一条id为1的数据,数据的内容就是删除的内容
比如我写了一条update ,把id为2的姓名从李四改成张三,那么undolog记录的就是 update - 把id为2的人的姓名改成李四

当执行rollback时,就直接调用对应的undolog,从而实现了内容的回滚。

Undo log销毁:undo log 在事务执行时产生,事务提交时,并不会立即删除undolog,因为这些日志还可能会用在MVCC中
Undo log存储:undo log采用段的方式进行管理和记录,存放在rollback segment回滚段中,其中包含了1024个undo log segment;

MVCC

当前读:读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁
比如:select lock in share mode,insert,delete

快照读:读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读
Read Committed:每次select 都生成一个快照都
Repeatable Read:开启事务后第一个select语句才是快照读的地方
Serializable:快照读都会退化为当前读

MVCC:
全程Multi-Version Concurrency Control ,多版本并发控制,指维护一个数据的多个版本,是的读写操作没有冲突,快照都为MySQL实现MVCC提供了一个非阻塞读的功能

MVCC的具体实现,还需要依赖于数据库记录的三个隐式字段,undolog,readView

MVCC实现原理

记录当中的隐藏字段
DB_TRX_ID: 最近修改十五ID,记录插入这条记录或最后一次修改该记录的事务ID
DB_ROLL_PTR:回滚指针,指向这条记录的上一个版本,用于配合undo log ,指向下一个版本
DB_ROLL_ID: 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段

看表结构的方法:

	ibd2sdi xx.ibd;

当然也可以用navicat直接看

undo log版本链

不同或相同事务对同一条数据进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,尾部是最早的旧记录

而具体要返回哪个版本,需要有readview决定
readview
读视图,是快照读sql执行时MVCC提取数据的依据,记录并维护系统当前活跃的事务(也就是未提交的事务)id

readview有四个核心字段:
m_ids: 当前活跃的事务ID集合
min_trx_id: 最小活跃事务ID
max_trx_id: 预分配事务ID,也就是当前最大事务ID+1
creator_trx_id: ReadView创建者的事务ID

版本链数据访问规则:
我们令当前事务ID为trx_id

  1. trx_id == creator_trx_id ? 可以访问该版本 -> 成立则说明数据是这个事务更改的
  2. trx_id < min_trx_id ? 可以访问该版本 -> 成立则说明该数据已经提交过了
  3. trx_id > max_trx_id ? 不可以访问该版本 -> 成立则说明该事务时在readview生成之后才开启的
  4. min_trx_id <= trx_id < max_trx_id ? 如果trx_id不在m_ids中是可以访问该版本的 -> 成立则说明数据已经提交了

不同隔离级别,生成readview的实际不同

读已提交:在事务中每次执行快照读时生成readview

可重复读:仅在事务中第一次执行快照读时生成readview,后续复用该readview

用readview生成后得到的四个核心字段,带入到上面的判断是否能访问的公式中,然后从undolog版本链由上到下依次寻找,那个版本符合就可以访问哪个版本

这就是MVCC,在快照读的时候决定使用哪个版本
而MVCC加上锁,就保证了数据的隔离性

一致性是由redo log 和 undo log共同保证的

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

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

相关文章

【PDF密码】PDF文件不能打印,为什么?

正常的PDF文件是可以打印的&#xff0c;如果PDF文件打开之后发现文件不能打印&#xff0c;我们需要先查看一下自己的打印机是否能够正常运行&#xff0c;如果打印机是正常的&#xff0c;我们再查看一下&#xff0c;文件中的打印功能按钮是否是灰色的状态。 如果PDF中的大多数功…

AWS——03篇(AWS之Amazon S3(云中可扩展存储)-01入门)

AWS——03篇&#xff08;AWS之Amazon S3&#xff08;云中可扩展存储&#xff09;-01入门&#xff09; 1. 前言2. 关于 Amazon S32.1 介绍2.1.1 简述2.1.2 详细介绍 2.2 Amazon S3 好处和功能2.3 3. 创建S3存储桶3.1 创建存储桶3.2 修改访问权限 4. 简单实用4.1 上传图片文件4.2…

iOS 实现图片高斯模糊效果

效果图 用到了 UIVisualEffectView 实现代码 - (UIVisualEffectView *)bgEffectView{if(!_bgEffectView){UIBlurEffect *blur [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];_bgEffectView [[UIVisualEffectView alloc] initWithEffect:blur];}return _bgEffect…

数据结构:栈的实现(C实现)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》 文章目录 前言一、栈的实现思路1. 结构的定义2. 初始化栈(StackInit)3. 入栈(StackPush)4. 出栈(StackPop)5. 获取栈顶元素(StackTop)6. 检查栈是否为空(StackEmpty)7. 销毁栈(StackDestroy) 二、…

UNIX网络编程卷一 学习笔记 第二十七章 IP选项

IPv4允许在20字节的首部固定部分后跟最多共40字节的选项。尽管已经定义了10种IPv4选项&#xff0c;但最常用的是源路径选项。我们可通过存取IP_OPTIONS套接字选项访问这些选项&#xff0c;我们存取该套接字选项时&#xff0c;所用的缓冲区中的值就是它们置于IP数据报中的格式。…

在QT及VS运行包含opencv的cmakelists实例

本文分享如何利用QT和Visual Studio运行cmake组织管理的程序&#xff0c;也就是运行cmakelists.txt。 main和cmakelists内容 main和cmakelists文件路径如下&#xff1a; main.cpp #include<opencv2/opencv.hpp> #include<iostream> #include <string> usi…

Linux:Shell编程之正则表达式

目录 绪论 1、正则表达式 1.1 通配符 1.2 正则表达式分类 1.3 基本正则 1.4 正则表达式中表示次数的表达式 1.5 位置锚定 1.5.1 词首锚定和词尾锚定 1.6 分组&#xff08;&#xff09; 1.7 逻辑或 1.8 扩展正则 绪论 正则表达式&#xff1a;有一类特殊字符以及文本…

Debian安装和使用Elasticsearch 8.9

命令行通过 .deb 包安装 Elasticsearch 创建一个新用户 adduser elastic --> rust # 添加sudo权限 # https://phoenixnap.com/kb/how-to-create-sudo-user-on-ubuntu usermod -aG sudo elastic groups elastic下载Elasticsearch v8.9.0 Debian 包 https://www.elastic.co/…

YOLOv5基础知识入门(3)— 目标检测相关知识点

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。YOLO算法发展历程和YOLOv5核心基础知识学习完成之后&#xff0c;接下来我们就需要学习目标检测相关知识了。为了让大家后面可以顺利地用YOLOv5进行目标检测实战&#xff0c;本节课就带领大家学习一下目标检测的基础知识点&…

使用Javassist实现热修复

工程目录图 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;LearnRobustFix

数据结构篇七:排序

文章目录 前言1.插入排序1.1 基本思想1.2 代码实现1.3 特性总结 2.希尔排序2.1 基本思想2.2 代码实现2.3 特性总结 3. 选择排序3.1 基本思想3.2 代码实现3.3 特性总结 4. 堆排序4.1 基本思想4.2 代码实现4.3 特性总结 5. 冒泡排序5.1 基本思想5.2 代码实现5.3 特性总结 6. 快速…

LeetCode 33题:搜索旋转排序数组

目录 题目 思路 代码 暴力解法 分方向法 二分法 题目 整数数组 nums 按升序排列&#xff0c;数组中的值 互不相同 。 在传递给函数之前&#xff0c;nums 在预先未知的某个下标 k&#xff08;0 < k < nums.length&#xff09;上进行了 旋转&#xff0c;使数组变为 …

提速Rust编译器!

Nethercote是一位研究Rust编译器的软件工程师。最近&#xff0c;他正在探索如何提升Rust编译器的性能&#xff0c;在他的博客文章中介绍了Rust编译器是如何将代码分割成代码生成单元&#xff08;CGU&#xff09;的以及rustc的性能加速。 他解释了不同数量和大小的CGU之间的权衡…

考虑微网新能源经济消纳的共享储能优化配置(Matlab代码实现

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

VSCode Remote-SSH (Windows)

1. VSCode 安装 VSCode 2. 安装扩展 Remote SSH Getting started Follow the step-by-step tutorial or if you have a simple SSH host setup, connect to it as follows: Press F1 and run the Remote-SSH: Open SSH Host… command.Enter your user and host/IP in the …

Sui网络的稳定性和高性能

Sui的最初的协议开发者设计了可扩展的网络&#xff0c;通过水平扩展的方式来保持可负担得起的gas费用。其他区块链与之相比&#xff0c;则使用稀缺性和交易成本来控制网络活动。 Sui主网上线前90天的数据指标证明了这一设计概念&#xff0c;在保持100&#xff05;正常运行的同…

实现Jenkins自动发包配置

参考抖音&#xff1a;Java不良人 其中的视频演示代码 不推荐把jenkins端口一直开放&#xff0c;推荐使用时候放开&#xff08;版本不太新&#xff0c;避免漏洞攻击&#xff09; [rootVM-4-12-centos soft]# docker-compose -v Docker Compose version v2.19.1docker-compose.…

提升效率!云原生生态从业人员不可或缺的工具集合!

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

​ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639)​

ATF(TF-A)安全通告汇总 目录 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639) 二、静态缓解&#xff08;Static mitigation&#xff09; 三、动态缓解&#xff08;Dynamic mitigation&#xff09; 一、ATF(TF-A)安全通告 TFV-7 (CVE-2018-3639) Title TF-A披露基于cache前瞻…

92. 反转链表 II

92. 反转链表 II 题目-中等难度示例1. 获取头 反转中间 获取尾 -> 拼接2. 链表转换列表 -> 计算 -> 转换回链表 题目-中等难度 给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点…