MySQL InnoDB 行记录存储结构分析

InnoDB存储结构这一篇就够了 本篇博文继续学习mysql的InnoDB引擎,主要内容分成三部分 1、对redo log、undo log、bin log的理解、2、针对插入和更新的 change buffer学习,3、InnoDB的逻辑存储结构:表空间(tablespace)、段(segment)、区(extend)、页(page)、行(row)等。 希望读者通过这篇文章能有所收获 阅读详情

前言

工作中我们基本上都是用MySQL的InnoDB存储引擎,但是大家有去了解过它的底层存储结构吗,想必绝大部分人不知道,或者说不知道怎么查相关知识,刚好来看这篇文章就对了!

数据表的文件构成

Mysql的存储行为是由Innodb存储引擎去具体实现的,在windows下安装Mysql后有data(数据库存放的地方)的文件夹,linux一般在/var/lib/mysql文件件。

创建数据库和表后我们可以在data目录先看到数据库对应名称文件夹,文件夹有opt、frm、ibd三种文件:

  • db.opt,用来存储当前数据库的默认字符集和字符校验规则。
  • demo1.frm ,t_order 的表结构会保存在这个文件
  • demo1.ibd,t_order 的表数据会保存在这个文件。表数据既可以存在共享表空间文件(文件名:ibdata1,在data目录下)里,也可以存放在独占表空间文件(文件名:表名字.ibd)

表空间的组成结构

先看图,先对表空间结构做个大概了解,形成一个概念

段

InnoDB存储引擎中,对段的管理都是由引擎自身所完成,我们已看到段有几种类型,它是不同类型的区组成的集合,一般分为索引段(B+树非叶子节点区)、数据段(B+树非叶子节点区)、回滚段(回滚数据区)。

也就是说InnoDB 对 B+ 树的叶节点和叶子节点进行了区别对待,也就是说叶子节点有自己独有的区,非叶子节点也有自己独有的区,如果不区分叶子节点和非叶子节点,统统把节点代表的页面放到申请到的区中的话,进行范围扫描的效率就大幅降低,而不同的区的集合就组成了不同的段。

区

我们知道B+树的每一层中的页都会形成一个双向链表,如果是以页为单位来分配存储空间的话,双向链表相邻的两个页之间的物理位置可能不是连续的,也许离得非常远,这种情况下进行 随机I/O 是会很慢的。

因此,应该尽量让链表中相邻的页的物理位置也相邻,这样进行范围查询的时候才可以使用所谓的 顺序I/O。

区在物理位置上由连续的64个页组成,InnoDB 中的页大小默认是 16KB,所以一个区的大小是 64*16KB= 1MB,这样使得页的双向链表在物理位置也是相邻的,从而进行顺序I/O,加快了查询效率!

在表数据量大的时候,为某个索引分配空间的时候就不再按照页为单位分配了,而是按区为单位分配,甚至在表中的数据特别多的时候,可以一次性分配多个连续的区。

页

Innodb读取数据的时候,并不是按照行来读取数据的,InnoDB 的数据是按【页】为单位来读写的,当需要读一条记录的时候,并不是将这个行记录从磁盘读出来,而是以页为单位,将其整体读入内存。

  1. InnoDB 的数据是按【页】为单位来读写的,也就是说,当需要读一条记录的时候,并不是将这个行记录从磁盘读出来,而是以页为单位,将其整体读入内存。
  2. 默认每个页的大小为 16KB,也就是最多能保证 16KB 的连续存储空间。
  3. 页是 InnoDB 存储引擎磁盘管理的最小单元,数据库每次读写都是以【页】为单位的,一次最少从磁盘中读取 16K 的内容到内存中。

行

MySQL也是以【行 row】进行存储的,图中对于行的描画图是 COMPACT格式,这也是重点需要了解的格式,而不同的行格式,存储的结构也不同。

InnoDB 行格式类型

行格式:就是记录在磁盘上的存放形式或者说存储结构

InnoDB 存储引擎设计了 4 种行格式,分别是 Redundant、Compact、Dynamic和 Compressed ,后三个都是紧凑型行格式,为的是存放更多的行记录。

Redundant 行格式比较古老了, MySQL 5.0 版本之前用的行格式,现在基本不用了,我们知道有这个格式就行了

Compact 行格式在MySQL 5.0 之后引入,在MySQL5.1版本中,默认设置为Compact行格式,一条完整的记录其实可以被分为记录的额外信息和记录的真实数据两大部分。

Dynamic 和 Compressed 它们的行格式都和 Compact 挺像,只是在 处理溢出列数据和Compact不同 ,MySQL5.7 版本之后,默认使用 Dynamic 行格式。

Compact 行格式图解

从上面我们知道Compact和Dynamic 和 Compressed很像,那么我们就Compact行格式展开进一步了解,了解了Compact就等同于对其他也做了了解。

从图中我们可以看到Compact行格式下,一条记录分为 【记录的额外信息】和【记录的真实数据】两部分,我们的列数据是在真实数据部分,我们再分别对这些内容进行更具体的描述。

记录的额外信息

额外信息为的是更好的管理记录,分为变长字段长度列表、NULL值列表、记录头信息

我们来创建一个表来看看变长字段具体是存的,表结构如下,行格式 Compact,本文对于行记录的实际存储案例基于这张表:

CREATE TABLE `demo1` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `col1` varchar(45) COLLATE utf8_bin DEFAULT NULL,
  `col2` varchar(45) COLLATE utf8_bin DEFAULT NULL,
  `col3` int(11) DEFAULT NULL,
  `col4` char(5) COLLATE utf8_bin DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=COMPACT;

并插入三条数据,demo1表中的各个列都使用的是ascii字符集(每个字符只需要1个字节来进行编码)

1:变长字段列信息

针对VARCHAR、TEXT、BLOB这类变长字段,列中实际存储了多少数据是不固定的,因此除了要把数据本身存下来,还需要记下它的长度,COMPACT将变长列的实际长度按照字段的顺序,逆序存储在变长字段长度列表里。

变长字段存储空间分为两部分:真正的数据部分、该数据占用的字节数

从demo1表的第一条记录来看各个字段占用的字节数,因为是变长字段, id、col3(int)、col(char)这三个字段可以不用管

  1. clo1字段是varchar ,值是zs,占用两个字节的空间,十六进制 0x02;
  2. clo2字段是varchar ,值是lsa,占用三个字节的空间,十六进制 0x03;

第一行行记录填入变长字段长度列表后的示意图如下:

逆序排列的目的是为了让位置靠前的记录的真实数据和数据对应的字段长度信息可以同时在一个 CPU Cache Line 中,这样就可以提高 CPU Cache 的命中率

2:NULL值列表

  1. 当某些字段是null值时,才显示在null值列表
  2. null值列表是通过bit位来进行标识的,一个字段占一个比特位,bit位按字段逆序排列
  3. 字段值为null的bit位为1,否则为0
  4. null 值列表必须用整数个字节的位表示(1字节8位),如果使用的二进制位个数不足整数个字节,则在字节的高位补 0

要注意的是null值列表并不是固定的1个字节,如果一条记录中有9个字段的值都是null,那么null值列表大小将是两个字节大小,依次类推。

结合这些特性,我们来看看一条记录中存在null值和不存在null值在null值列表中的样子,我们记录使用上面表demo1的结构和数据,其中id是主键不能为null,不在讨论范围内,表中null字段不超过8个,这三条记录对应的null值列表如下:

第一条记录:

第二条记录:

第三条记录:

3:记录头信息

记录头其实包含了很多信息,如图,我们着重了解红色部分几个比较重要的。

  • delete_flag :删除标记 0未删除、1已删除,我们执行 detele 删除记录的时候,并不会真正的删除记录,只是将这个记录的 delete_flag 标记为 1。 (所有的被删除掉的记录会组成一个垃圾链表,记录在这个链表中占用的空间被称为可重用空间。之后若是有新的记录插入到表中,它们就可以覆盖掉被删除的这些记录占用的存储空间了)
  • next_record:记录与记录之间是通过链表组织的,它表示当前记录的真实数据到下一条记录的真实数据的距离,指向的是下一条记录的「记录头信息」和「真实数据」之间的位置。 这个位置刚好向左读就是记录头信息,向右读就是真实数据,该值为【正】表示下一条记录在它的后面,为【负】表示下一条记录在它的前面(这里都是按字节去找位置)
  • record_type:表示当前记录的类型,0:表示普通记录,1:表示B+树非叶子节点记录,2:表示最小记录(Infimum),3:表示最大记录(Supremum)

记录的真实数据

我们看隐藏字段 row_id、trx_id、roll_ptr 感觉是不是在哪里遇到过,只要你了解过Mysql的MVCC机制就很熟悉这几个字段

  • row_id:如果我们指定了主键或者唯一约束列,那么就没有 row_id 隐藏字段了。如果既没有指定主键,又没有唯一约束,InnoDB 才会为记录添加 row_id 隐藏字段。row_id不是必需的,占用 6 个字节。
  • trx_id:记录创建这条记录/最后一次修改该记录的事务 ID, trx_id是必需的,占用 6 个字节。
  • roll_ptr:回滚指针,记录的是记录上一个版本的指针,roll_ptr 是必需的,占用 7 个字节。

其他字段就是我们创建表的时候定义的各个列字段了。

总结

通篇下来,感觉对InnoDB实际的存储结构有了更深的认识,当然也会产生不少问题,比如:

1:一行记录除了 TEXT、BLOBs 类型的列,限制最大为 65535 字节,那么能具体分析分析吗?

2:行溢出了会怎么样,因为一页就16kb,16384字节,是小于65535 字节的

3:为什么设计表的时候字段会选择not null?

等等,这些问题将会在下次进行总结,就不在这里用大篇幅展开了,毕竟一次看文字少点看得不会那么累!

文末安利一波:

欢迎朋友们关注我的同名公众号📢📢:【小许code】,等你哦!🤣🤣

欢迎点赞 👍、收藏 💙、关注 💡 三连支持一下~🎈

🎈知道的越多,不知道的也越多,我是小许,下期见~🙇💻

参考资料:

《MySQL 是怎样运行的》

InnoDB的存储结构

MYSQL-INNODB索引构成详解 对于MYSQL的INNODB存储引擎的索引,大家是不陌生的,都能想到是 B+树结构,可以加速SQL查询。但对于B+树索引,它到底“长”得什么样子,它具体如何由一个个字节构成的,这些的基础知识鲜有人深究。本篇文章从MYSQL行记录开始说起,层层递进,包括数据页,B+树聚簇索引,B+树二级索引,最后在文章末尾给出MYSQL索引的建议。文章涉及较多基础知识,内容较为枯燥,因此采用较多的图片补充说明,希望能对读者有帮助。 阅读详情

相关推荐

Mysql探索(二)之InnoDB底层存储结构

了解mysql底层存储结构,知道db数据是怎么存储的,这对于深入了解mysql底层运行原理尤为关键,一看到crud操作时,脑海若能浮现底层数据运作情况,则为绝佳。如果懂得索引,buffer,log等InnoDB底层技术,再看这篇,相信也会有意想不到的收获。...

zdjsswqs的博客 1126

mysql原理--InnoDB记录结构

行记录,Compact

x13262608581的博客 1292

【STM32】基于STM32F103C8T6实现步进电机精准调速控制

本文详细介绍了如何使用STM32F103C8T6微控制器实现步进电机的精准调速控制。通过利用其内置定时器生成PWM脉冲,替代低效的延时方法,并结合TB6600驱动器进行硬件连接,可实现平滑、高效的电机速度控制。文章提供了基于HAL库的代码实战,包括速度与方向设置函数,并探讨了加减速规划等高级应用,帮助开发者彻底掌握步进电机驱动技术。

weixin_29169899的博客 486

《MySQL高级篇》一、MySQL的目录结构

《MySQL高级篇》一、MySQL的目录结构

LXYDSF的博客 2899

告别手动维护!教你用SAP BAPI批量更新生产订单BOM组件(CO02工单)

本文详细介绍了如何利用SAP BAPI实现生产订单BOM组件的批量更新,解决传统手工操作(如CO02工单)效率低下的问题。通过核心函数解析和批量处理框架设计,帮助用户大幅提升工作效率,降低错误率,适用于物料主数据变更、季节性配方调整等场景。

weixin_30844577的博客 561

Android Studio安装常见问题详解——Android Emulator Hypervisor Driver for AMD Processors installation failed.

目录一、问题描述二、解决方案2.1 开启CPU虚拟化2.2 禁用Hyper-V2.3 使用管理员命令行在驱动程序包中执行“silent_install.bat” 一、问题描述 新买的AMD轻薄本,在安装Android Studio时遇到问题: Android Emulator Hypervisor Driver for AMD Processors installation failed. 笔记本配置为: 二、解决方案 2.1 开启CPU虚拟化 设置虚拟化的步骤这里不进行详细介绍了。如果需要,可以自行百

Wendy的博客 4万+

【MySQL】InnoDB的存储结构

InnoDB的存储结构:每个表都会生成一个表空间文件,这个文件里面最小结构就是行,存储的真正的数据,一个页来管理若干行,一个区来管理若干页,一个区组来管理若干区。段并不是真正的物理存储结构,它只是把这些数据结构划分成两部分(B+树的叶子节点和非叶子节点)。

p_fly的博客 1159

HTML流光爱心(完整代码)

HTML语言实现红蓝色流光爱心效果的完整代码。

AIGC 1万+

MySQL表的结构信息存储在哪里?

表结构定义占有的存储空间比较小,在 MySQL 8 之前,表结构的定义信息存在以 .frm 为后缀的文件里,在 MySQL 8 之后,则允许把表结构的定义信息存在系统数据表之中。在 MySQL 中,表的结构信息存储在系统表中。系统表是特殊的数据库表,用于存储关于数据库对象(如表、列、索引、触发器等)的元数据信息。:该表存储了数据库中所有表的信息,包括表名、所属数据库、表的引擎类型、表的行数、创建时间等。:该表包含了数据库中所有表的列信息,包括表名、列名、数据类型、约束条件、默认值等。

学亮编程手记 1704

【面试系列】软件架构师 高频面试题及详细解答

本文介绍了软件架构师岗位的初级、中级和高级面试题及详细解答,涵盖了系统设计、面向对象设计、分布式系统、云计算技术、性能优化等关键领域。通过这些问题和解答,候选人可以深入理解软件架构师的核心职责和技能要求。此外,文章总结了在面试中需要掌握的常考知识点,包括架构模式、分布式系统管理、安全性、数据管理和DevOps实践。通过掌握这些知识点,软件架构师能够有效设计和指导复杂系统的结构,确保系统的可扩展性、性能和维护性。

在路上的专栏 850

vue2 - 详细实现播放AMR格式音频并实现自定义播放器样式,支持amr音频文件在线地址URL播放、调用服务端API接口获取二进制文件流amr形式、用户本地上传amr文件并实现立即播放(详细代码)

vue2,amr,amr文件播放,vue播放amr音频文件以及在线url跨域问题解决,vue使用audio标签播放amr音频,amr跨域解决,amr网页解码播放,文件上传后怎么播放,vue2播放.amr语音文件,api接口形式调用获取的amr如何播放,vue中如何使用audio元素播放AMR格式的文件,进度条,vue前端如何播放AMR格式的音频文件,vue播放语音文件AMR格式,播放amr格式音频AMR录音机,h5原生audio播放amr格式的音频,VUE2使用benz-amr-recorder 实现解码、

✅ 精选推荐文章 7414

MySQL—InnoDB记录结构

MySQL—InnoDB的记录结构 一、InnoDB页概述 InnoDB是用来把内存中表的数据存储到磁盘上、把磁盘上的数据加载到内存中供用户使用的存储引擎。因为磁盘与内存的速度差了几个量级,所以InnoDB存储引擎在进行IO操作时,不可能一条一条记录进行读取或写入,如果一条一条记录进行IO的话,用户可能会骂娘。所以为了解决内存与磁盘速度不匹配问题,InnoDB采用的方式是:将数据划分为若干个页,这个页就是内存与磁盘交互的基本单位,即内存读取或写入一次磁盘,就是读取或写入若干个页,InnoDB中每个页的大小一

多一天,多一点 893

ESP32 DW1000 UWB 室内定位系统

详细介绍ESP32 DW1000 UWB 室内定位系统的设计演示demo。

DT程序员的博客 1662

分析MySQL InnoDB 行记录存储结构

InnoDB 存储引擎设计了 4 种行格式,分别是 Redundant、Compact、Dynamic和 Compressed

xiaoxucode的博客 116

Vue3 - Element Plus 下拉选择器 el-select 覆盖修改 placeholder样式,解决覆盖不生效问题(支持修改文字颜色、文字大小、选择器边框、hover效果、宽高等任意样式

vue3,element-plus,el-select,下拉选择器,下拉选择框,Select选择器,deep覆盖无效怎么办,怎么修改placeholder文字颜色,选择器select修改边框样式,修改文字大小,elementPlus选择器如何覆盖hover效果,使用deep改不了样式,修改边框颜色,select去掉边框,vue3+elementPlus中select选择器如何修改placeholder文字样式,修改el-select样式,select选择器样式覆盖不了咋办,el-select如何覆盖原样式,

🏆 前端领域优质创作者 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

mysql innodb 表空间物理存储结构及内部逻辑组织结构

在物理存储层面,每个mysql的表(非系统表)就是.frm文件及一个.ibd文件(前提是开启了独立表空间)。在物理层面就是一个二进制文件。 在这个二进制文件的基础上,分析其内部逻辑组织结构。 文章目录表空间 tablespace段 segment区 extent页页记录格式1. file Header2. Page Header3. lnfimum 和Supremum Record4. User Record5. Free Space6. Page Directory7. File Trailer行/记

u013905744的专栏 1939

怀旧版电脑GBC模拟器

再现原版GBC掌机的界面,电脑运行连游戏界面都一样大小,很怀旧,很真实,(英文版)强烈推荐,很小的文件,很难才找到的。

《MySQL系列-InnoDB引擎04》MySQL表相关介绍

从InnoDB存储引擎表的逻辑存储及实现开始进行介绍,然后将重点分析表的物理存储特征,即数据在表中是如何组织和存放的。简单来说,表就是关于特定实体的数据集合,这也是关系型数据库模型的核心

https://blog.datasource.space 1402

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

洞悉MySQL底层架构:游走在缓冲与磁盘之间

觉得写的很好,特转载便记录。提起MySQL,其实网上已经有一大把教程了,为什么我还要写这篇文章呢,大概是因为网上很多网站都是比较零散,而且描述不够直观,不能系统对MySQL相关知识有一个系统的学习,导致不能形成知识体系。为此我撰写了这篇文章,试图让这些底层架构相关知识更加直观易懂:好了,MySQL从不会到精通系列马上就要开始了(看完之后还是不会的话..请忽略这句话)。正在上传…重新上传取消可能会有同学问:为啥不直接学更加先进的TiDB,或者是强大的OceanBase。其实,MySQL作为老牌的应用场景广泛

杨小猪 的博客 1193

为什么Kafka不需要我们关心索引,而Mysql却需要?

不管是啥业务,最终数据都要落地,数据库这一环是肯定少不了的。随着业务发展,并发越来越高,数据库很容易成为整个链路的短板。这也是大厂面试中比较常被问到的。而调优的第一步,都是从sql语句、索引入手。先得保证单个数据库执行没问题,才会有更高层次的分库分表、弹性、容灾等等。 # 为什么Kafka不需要我们关心索引,而Mysql却需要? Kafka 和 MySQL 虽然最终数据都是落磁盘,但是两者在用途和数据查询方式上有着很大的差异,所以决定了数据的存储结构不同,进而决定了索引的复杂程度。 我们先

Javazzc123的专栏 514

【MySQL InnoDB读书笔记】08 InnoDB下逻辑存储结构(一)

表、段、表空间、区、记录、Compact、Redundant、Compressed、Dynamic

宫瑞阳的博客 1525

3K字详解MySQL InnoDB 行记录存储结构

工作中我们基本上都是用MySQL的InnoDB存储引擎,但是大家有去了解过它的底层存储结构吗,想必绝大部分人不知道,或者说不知道怎么查相关知识,刚好来看这篇文章就对了!通篇下来,感觉对InnoDB实际的存储结构有了更深的认识,当然也会产生不少问题,比如:1:一行记录除了 TEXT、BLOBs 类型的列,限制最大为 65535 字节,那么能具体分析分析吗?2:行溢出了会怎么样,因为一页就16kb,16384字节,是小于65535 字节的3:为什么设计表的时候字段会选择not null?

wdj_yyds的博客 170

深入学习MySQL(4)InnoDB存储结构

这一节本来计划开始索引的学习,但是在InnoDB存储引擎的索引里,存在一些数据存储结构的概念,这一节先了解一下InnodDB的逻辑存储结构,为索引的学习打好基础。从InnoDB存储引擎的存储结构看,所有数据都被逻辑地放在一个空间中,称之为表空间(tablespace)、区(extent)、页(page)组成,页在一些文档中也被称之为块(block)。

mifffy_java的博客 1030

MySQL提升笔记(4)InnoDB存储结构

MySQL提升笔记第四篇,介绍MySQL默认存储引擎InnoDB的逻辑存储结构。从表空间(tablespace)向下,到区(extent)、页(page)、行(row),一步步揭开MySQL数据存储的面纱。

三分恶的博客 1107

【MySQL】InnoDB 基本了解+存储结构

InnoDB引擎基本了解 + MySQL存储结构

gma999的博客 1374

MySQL高级进阶:关于InnoDB存储结构,一文深入分析讲解

在InnoDB存储引擎的索引里,存在一些数据存储结构的概念,这一节先了解一下InnodDB的逻辑存储结构,为索引的学习打好基础。从InnoDB存储引擎的存储结构看,所有数据都被逻辑地放在一个空间中,称之为表空间(tablespace)、区(extent)、页(page)组成,页在一些文档中也被称之为块(block)。

m0_62051288的博客 727

MySQL 篇-深入了解 InnoDB 引擎的逻辑存储结构、架构、事务原理、MVCC 原理分析(RC 级别、RR 级别)

需要注意的是,此时修改之后的数据页在缓冲区中,是根据一定的时间才将脏数据页刷新到磁盘中,而不是数据修改完之后马上刷新的,也不是提交事务完之后马上提交的。2)Change Buffer:更改缓冲区(针对于非唯一的二级索引页),在执行 MDL 语句时,如果这些数据 Page 没有在 Buffer Pool 中,不会直接操作磁盘,而会将数据变更存放到更改缓冲区 Change Buffer 中,在未来数据被读取时,再将数据合并恢复到 Buffer Pool 中,再将合并后的数据刷新到磁盘中。

小扳手 1万+
上一篇: Go项目目录结构应该这么用!
下一篇: 【干货】Mysql索引知识看这里就明白了!
小许code
博客等级 码龄3年 286粉丝 20原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值