【MySQL】InnoDB存储引擎详解

news2025/9/19 15:34:22

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.coloradmin.cn/o/863017.html

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

相关文章

使用KETTLE工具在Oracle和Dm8之间迁移数据

oracle 代码测试数据 CREATE TABLE PRODUCT_CATEGORY ( PRODUCT_CATEGORYID NUMBER(11,0) NOT NULL , NAME VARCHAR2(255) NOT NULL ENABLE, PRIMARY KEY (PRODUCT_CATEGORYID) )INSERT ALL into PRODUCT_CATEGORY(PRODUCT_CATEGORYID, NAME)VALUES(2,国学) into PRODUCT_CATEG…

可以重复烧写的语音ic有哪些特征和优势

目录 一、简介可擦写的语音芯片&#xff0c;其实就是MCUflash的架构&#xff0c;无其他说法&#xff0c;就这一种说法。这个就是它最大的特征尤其是SOP8的封装类型的芯片&#xff0c;是区别于OTP类型的另一个品类&#xff0c;基本上OTP的语音芯片适用的场景。他都可以满足和替代…

【冒泡排序及其优化】

冒泡排序及其优化 冒泡排序核心思想 冒泡排序的核⼼思想就是&#xff1a;两两相邻的元素进⾏⽐较 1题目举例 给出一个倒序数组&#xff1a;arr[10]{9,8,7,6,5,4,3,2,1,0} 请排序按小到大输出 1.1题目分析 这是一个完全倒序的数组&#xff0c;所以确定冒泡排序的趟数&#xff0…

机器学习笔记之优化算法(十三)关于二次上界引理

机器学习笔记之优化算法——关于二次上界引理 引言回顾&#xff1a;利普希兹连续梯度下降法介绍 二次上界引理&#xff1a;介绍与作用二次上界与最优步长之间的关系二次上界引理证明过程 引言 本节将介绍二次上界的具体作用以及它的证明过程。 回顾&#xff1a; 利普希兹连续…

svg圆形进度条

css3实现的圆形进度条较复杂&#xff0c;代码量较多&#xff0c;本文稍微讲解下如何使用svg实现圆形进度条。 svg实现一个圆用<circle>元素&#xff1a; <svg viewBox"0 0 100 100" xmlns"http://www.w3.org/2000/svg"><circle cx"50…

腾讯云服务器CPU标准型S5/S6/SA3/SR1/SA2处理器大全

腾讯云服务器CVM标准型CPU处理器大全&#xff0c;包括标准型S6、SA3、SR1、S5、S5se、SA2、S4、SN3ne、S3、SA1、S2ne实例CPU处理器型号大全&#xff0c;标准型S6云服务器CPU采用Intel Ice Lake(2.7GHz/3.3GHz)&#xff0c;标准型S5采用Intel Xeon Cascade Lake 8255C/Intel Xe…

day4 USART串口的应用

同步和异步通信 通信&#xff0c;最少要有两个对象&#xff0c;一个收&#xff0c;一个发。 同步通信&#xff1a;一般情况下同步通信指的是通信双方根据同步信号进行通信的方式。比如通信双方有一个共同的时钟信号&#xff0c;大家根据时钟信号的变化进行通信。 异步通信&…

Stable Diffusion - 幻想 (Fantasy) 风格与糖果世界 (Candy Land) 人物提示词配置

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/132212193 图像由 DreamShaper8 模型生成&#xff0c;融合糖果世界。 幻想 (Fantasy) 风格图像是一种以想象力为主导的艺术形式&#xff0c;创造了…

2023MacBook电脑清理垃圾软件CleanMyMac X

用久了的MacBook&#xff0c;会出现系统反应缓慢卡顿等现象&#xff0c;这主要原因是系统垃圾的堆积。MacBook清理&#xff0c;就很有必要了&#xff0c;特别的垃圾清理。因此&#xff0c;定期清理这些垃圾文件是保持MacBook高效运行的重要任务之一。本文将介绍一些高效的方法&…

【LeetCode】122. 买卖股票的最佳时机 II - 贪婪算法

目录 2023-8-10 10:29:32 122. 买卖股票的最佳时机 II 2023-8-10 10:29:32 没错&#xff0c;还是用双指针思想来套出来的。 感觉步骤很复杂&#xff0c;还调试了半天。 class Solution {public int maxProfit(int[] prices) {int pre 0;int last 1;int maxProfit 0;int c…

timerfd和timer

note timerfd对应的时钟到期后&#xff0c;对应内部数据(uint64)计数加1 timerfd支持read方法&#xff0c;poll方法 code #include <sys/timerfd.h> #include <poll.h> #include <thread> #include <stdio.h> #include <string.h> #include …

代码随想录算法训练营day29 | 491. 递增子序列,46. 全排列,47. 全排列 II

目录 491. 递增子序列 46. 全排列 47. 全排列 II 491. 递增子序列 难度&#xff1a;medium 类型&#xff1a;回溯&#xff0c;类子集问题 思路&#xff1a; 因为不能排序&#xff0c;所以不能使用 40. 组合总和 II 的去重方式。使用hashset来对递归树的某一层去重。 代码…

为什么要学习Oracle技术?

为什么要学习Oracle技术? 众所周知&#xff0c;Oracle占据着企业数据库领域超过48.1%的市场份额&#xff0c;成为高端企业数据库软件的绝对领导者。随着时间的推移&#xff0c;企业数据库的规模不断扩大&#xff0c;富有经验的资深OracleDBA越来越受到企业的欢迎。我们从著名的…

cmake基础(2)——动/静态库

一、静态库创建 1. 准备 首先创建目录和文件结构如下&#xff1a; 文件内容如下&#xff1a; class Hello { public:void print(); }; #include "hello.h" #include <iostream>void Hello::print() {std::cout << "hello world!" <<…

详细记录Pycharm配置已安装好的Conda虚拟环境

当安装好conda环境之后&#xff0c;想要在Pycharm中使用&#xff0c;那么就要在Pycharm中导入&#xff0c;我这里使用的pycharm-professional-2023.2这个版本&#xff0c;下面是详细步骤&#xff1a; 1.打开File->Settings&#xff1a; 2.找到Project——>Python Inter…

javascript获取设置输入框内容

代码&#xff0c; <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>获取设置输入框内容</title> </head> <body><button onclick"getinput()">click me</button><div id&qu…

float 属性的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ float 是什么&#xff1f;⭐ float 属性值⭐ 使用 float 的注意事项&#xff1a;⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门…

FPGA优质开源项目 – PCIE通信

本文介绍一个FPGA开源项目&#xff1a;PCIE通信。该工程围绕Vivado软件中提供的PCIE通信IP核XDMA IP建立。Xilinx提供了XDMA的开源驱动程序&#xff0c;可在Windows系统或者Linux系统下使用&#xff0c;因此采用XDMA IP进行PCIE通信是比较简单直接的。 本文主要介绍一下XDMA I…

平替 Docker - 玩转容器新利器 Podman Desktop (视频)

《OpenShift 4.x HOL教程汇总》 在 podman-desktop 1.2.1 podman 4.4 环境中验证。 文章目录 什么是 podman 和 podman-desktop安装 podman 和 podman-desktop 基本环境Image、Container 和 Pod 的基本操作拉取 Image运行 Container 将 Pod 部署到 Kubernetes安装 Kind 扩展插…

【数学建模】--因子分析模型

因子分析有斯皮尔曼在1904年首次提出&#xff0c;其在某种程度上可以被看成时主成分分析的推广和扩展。 因子分析法通过研究变量间的相关稀疏矩阵&#xff0c;把这些变量间错综复杂的关系归结成少数几个综合因子&#xff0c;由于归结出的因子个数少于原始变量的个数&#xff0c…