【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共同保证的

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

宋浩概率论笔记(四)数字特征

本帖更新数字特征&#xff0c;包含期望、方差、相关系数等&#xff0c;要点在于记忆性质中的各种公式&#xff0c;遇到题目时能迅速利用已知条件计算答案。

PXE-kickstart无人值守安装操作系统

PXE的概念&#xff1a; PXE&#xff08;Pre-boot Execution Environment&#xff0c;预启动执行环境&#xff09;是由Intel公司开发的最新技术&#xff0c;工作于C/S的网络模式&#xff0c;支持工作站通过网络从远端服务器下载映像&#xff0c;并由此支持通过网络启动操作系统…

QT网络编程之TCP

QT网络编程之TCP TCP 编程需要用到俩个类: QTcpServer 和 QTcpSocket。 #------------------------------------------------- # # Project created by QtCreator 2023-08-

生产执行MES系统:提升企业灵活性和响应速度的关键利器

在竞争激烈的市场环境下&#xff0c;企业需要不断提高其灵活性和响应速度&#xff0c;以适应快速变化的需求和市场动态。生产执行MES&#xff08;Manufacturing Execution System&#xff09;系统作为信息技术的重要应用&#xff0c;为企业提供了强大的工具和平台&#xff0c;能…

【JavaScript】new 的原理以及实现

网道 - new 命令的原理 使用new命令时&#xff0c;它后面的函数依次执行下面的步骤。 创建一个空对象&#xff0c;作为将要返回的对象实例。将这个空对象的原型&#xff0c;指向构造函数的prototype属性。将这个空对象赋值给函数内部的this关键字。如果构造函数返回了一个对象…

开封Geotrust单域名https证书推荐

Geotrust作为全球领先的数字证书颁发机构之一&#xff0c;拥有多年的数字证书颁发经验&#xff0c;其数字证书被广泛应用于电子商务、在线支付、企业通讯、云计算等领域&#xff0c;为用户提供了安全可靠的保障。而Geotrust旗下的单域名https证书是大多数客户创建网站时的选择之…

java spring cloud 企业电子招标采购系统源码:营造全面规范安全的电子招投标环境,促进招投标市场健康可持续发展 tbms

​ 项目说明 随着公司的快速发展&#xff0c;企业人员和经营规模不断壮大&#xff0c;公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境&#xff0c;最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范&#xff0c;以…

vscode关闭绑定元素“xxx”隐式具有“any”类型这类错误

在ts的项目里面&#xff0c;真的经常看到any类型的报错&#xff0c;真的很烦的 所以为了眼不见心不乱&#xff0c;我决定消除这个错误提示 在tsconfig.json里面配置 "noImplicitAny": false 就可以了 {"compilerOptions": {"target": "E…

Unity-Shader-高亮Highlight

常用Shader-高亮&#xff0c;可动态调整高亮颜色、高亮强度范围/等级、高亮闪烁速度、高亮状态 Shader "CustomShader/Highlight" {Properties{_Color("Color", Color) (0.9044118,0.6640914,0.03325041,0)_Albedo("Albedo", 2D) "white…

如何创造千亿项目?合法合规的绿色消费增值积分,或许能冲出赛道

电商行业的竞争越来越激烈&#xff0c;大部分的电商平台都面临着这三大难题&#xff1a;如何吸引用户、如何留存用户以及如何让用户为平台带来更多的效益。为了解决这三大问题&#xff0c;我们提出了创造千亿项目的商业模式——绿色消费增值积分系统&#xff0c;帮助企业冲出赛…

golang内存对齐

为什么要内存对齐&#xff1f; CPU访问内存时&#xff0c;以CPU的位数为单位进行访问。 如果访问未对齐的内存&#xff0c;处理器需要做两次内存访问&#xff0c;对齐的内存的访问可能仅需要一次&#xff0c;利用内存对齐后提升读取速度。 golang结构体内存对齐规则 在代码编译…

SpringBoot05--axios网络请求

浏览器主动发送请求&#xff0c;服务器接收请求之后返回数据&#xff0c;通过vue进行数据绑定 请求成功&#xff0c;返回的数据会包装到response里面去&#xff08;返回成response的data属性&#xff09; 好的这边不太懂 在xxx.vue组件被创建和挂载&#xff08;渲染&#xff09…

解决createRoot is not a function

报错&#xff1a; 出现的原因&#xff1a;在于把react18使用的vite构建&#xff0c;在开发中因react版本太高与其他库不兼容&#xff0c;而在降级的时候&#xff0c;出现以上dom渲染出现报错。 解决&#xff1a;将 src/index.j文件改成如下 import React from react; import…

LVS-DR模式集群构建过程演示

一、工作原理 LVS的工作原理 1.当用户向负载均衡调度器&#xff08;Director Server&#xff09;发起请求&#xff0c;调度器将请求发往至内核空间 2.PREROUTING链首先会接收到用户请求&#xff0c;判断目标IP确定是本机IP&#xff0c;将数据包发往INPUT链 3.IPVS是工作在IN…

工程管理系统简介 工程管理系统源码 java工程管理系统 工程管理系统功能设计em

工程项目管理软件&#xff08;工程项目管理系统&#xff09;对建设工程项目管理组织建设、项目策划决策、规划设计、施工建设到竣工交付、总结评估、运维运营&#xff0c;全过程、全方位的对项目进行综合管理 工程项目各模块及其功能点清单 一、系统管理 1、数据字典&#xff…

初出茅庐的小李博客之认识编码器

编码器是什么&#xff1a; 一种将角位移或者角速度转换成一连串电数字脉冲的旋转式传感器&#xff0c;我们可以通过编码器测量到底位移或者速度信息。编码器通常由一个旋转部分和一个固定部分组成&#xff0c;旋转部分随着被测量的物体进行旋转&#xff0c;固定部分则保持不动…

MySql(干货)

写这篇博客的目的不是为了将介绍原理&#xff0c;而是为了Sql中的代码操作属实太多了&#xff0c;在这里进行一个汇总&#xff0c;方便查阅&#xff01;&#xff01;&#xff01; Sql分类 分类全称说明 DDL Data Definintion Language数据定义语言&#xff0c;用来定义数据库对…

wireshark入门指北

文章目录 前言安装Linux上wireshark安装 使用捕获的时候添加过滤条件抓取浏览器https内容 附录抓取非浏览器的https流量 前言 本文长期维护&#xff0c;记录使用wireshark的使用过程。 虽然有官方文档-Wireshark User’s Guide&#xff0c;但是不想去慢慢读。应用层的图形软件…

Flutter:文件上传与下载(下载后预览)

Dio dio是一个强大的Dart Http请求库&#xff0c;提供了丰富的功能和易于使用的API&#xff0c;支持文件上传和下载。 这个就不介绍了&#xff0c;网上有很多的封装案例。 background_downloader 简介 适用于iOS&#xff0c;Android&#xff0c;MacOS&#xff0c;Windows和L…

el-dialog嵌套,修改内层el-dialog样式(自定义样式)

el-dialog嵌套使用时,内层的el-dialog要添加append-to-body属性 给内层的el-dialog添加custom-class属性,添加自定义类名 <el-dialog:visible.sync"dialogVisible"append-to-bodycustom-class"tree-cesium-container"><span>这是一段信息<…