【MySQL】行结构详解:InnoDb支持格式、如何存储、头信息区域、Null列表、变长字段以及与其他格式的对比

📢博客主页:https://blog.csdn.net/2301_779549673
📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson
📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正!
📢本文由 JohnKi 原创,首发于 CSDN🙉
📢未来很长,值得我们全力奔赴更美好的生活✨

在这里插入图片描述

在这里插入图片描述

文章目录

  • 🏳️‍🌈一、InnoDB支持的数据行格式都有哪些?
    • 1.1 如何查看当前数据库或表应用了哪种行格式?
    • 1.2 如何指定行格式?
    • 1.3 DYNAMIC 格式由哪些部分组成?
  • 🏳️‍🌈二、数据区是怎么存储真实数据的?
  • 🏳️‍🌈三、额外(管理)信息区包含了关于行的哪些信息?
  • 🏳️‍🌈四、头信息区域包含了哪些信息?
    • 4.1 删除一行记录时在InnoDB内部执行了哪些操作?
  • 🏳️‍🌈五、NuIl列表有啥作用? 列表中的值是什么?
  • 🏳️‍🌈六、变长字段列表有啥作用?列表中的值是什么?
    • 6.1 如何记录变长字段的实际长度?
    • 6.2 读取长度时如何处理粘包问题?
  • 🏳️‍🌈七、其他的行格式与 DYNAMIC 有什么区别?
    • 7.1 REDUNDANT 冗余格式
    • 7.2 COMPRESSED 压缩格式
    • 7.3 COMPACT 紧凑格式
  • 👥总结


真实的数据在表空间以数据行的形式存储,也就是说每一条数据都对应着表中的一行,数据行在页中的位置如下图所示:

在这里插入图片描述

🏳️‍🌈一、InnoDB支持的数据行格式都有哪些?

InnoDB 支持四种行格式,分别是: REDUNDANT 冗余格式COMPACT 紧凑格式DYNAMIC 动态格式COMPRESSED 压缩格式

默认是 DYNAMIC 格式。

1.1 如何查看当前数据库或表应用了哪种行格式?

# 查看系统变量中设置的⾏格式
mysql> SHOW VARIABLES LIKE 'innodb_default_row_format';
+---------------------------+---------+
| Variable_name             | Value   |
+---------------------------+---------+
| innodb_default_row_format | dynamic |
+---------------------------+---------+
1 row in set (0.00 sec)
# 使⽤SHOW table STATUS查看数据库中的所有表
mysql> SHOW TABLE STATUS IN test_db\G
*************************** 1. row ***************************Name: classesEngine: InnoDBVersion: 10Row_format: Dynamic				# 指定数据库使⽤的⾏格式Rows: 3Avg_row_length: 5461Data_length: 16384
Max_data_length: 0Index_length: 0Data_free: 0Auto_increment: 4Create_time: 2025-05-02 19:14:14Update_time: NULLCheck_time: NULLCollation: utf8mb4_general_ciChecksum: NULLCreate_options: row_format=DYNAMICComment: 
*************************** 2. row ***************************Name: courseEngine: InnoDBVersion: 10Row_format: DynamicRows: 6Avg_row_length: 2730Data_length: 16384
Max_data_length: 0Index_length: 0Data_free: 0Auto_increment: 7Create_time: 2025-05-02 19:14:14Update_time: NULLCheck_time: NULLCollation: utf8mb4_general_ciChecksum: NULLCreate_options: row_format=DYNAMICComment: 
*************************** 3. row ***************************Name: scoreEngine: InnoDBVersion: 10Row_format: DynamicRows: 15Avg_row_length: 1092Data_length: 16384
Max_data_length: 0Index_length: 0Data_free: 0Auto_increment: NULLCreate_time: 2025-05-02 19:14:14Update_time: NULLCheck_time: NULLCollation: utf8mb4_general_ciChecksum: NULLCreate_options: row_format=DYNAMICComment: 
# ... 省略
16 rows in set (0.06 sec)

1.2 如何指定行格式?

  • 可以通过 全局变量 设置行格式
  • 也可以在创建表中通过 ROW_FORMAT 子句指定行格式:
# 通过全局变量设置
SET GLOBAL innodb_default_row_format=DYNAMIC;# 在创建表时明确的指定⾏格式
CREATE TABLE t1 (c1 INT) ROW_FORMAT=DYNAMIC;

1.3 DYNAMIC 格式由哪些部分组成?

一个 DYNAMIC 格式的数据行会被分为两部分

  • 一部分是存储 真实数据 的区域
  • 一部分是存储 额外信息 的区域

在页结构的小节已经对行做了简单介绍,下面来详细讲解一下行的组成结构

🏳️‍🌈二、数据区是怎么存储真实数据的?

数据区在数据行中的位置如下图所示:
在这里插入图片描述

从分隔线向右第一个字段存储真实数据的主键值,对于 主键值 有以下几种情况:

  • 如果表中定义了主键,则直接存储 主键 的值;。
  • 如果是复合主键根据列定义的顺序 依次排列在这里;
  • 如果没有主键,会优先使用 第一个不允许为 NULL 的 UNIQUE 唯一列 作为主键;
  • 如果既没有主键也没有唯一键,那么InnoDB会构建一个6字节的字段 DB_ROW_ID 作为行的唯一标识,存储在真实数据的头部

紧接着是在事务运行中两个非常重要的固定字段

  • 6字节的事务ID字段 DB_TXID,记录创建或最后一次修改该记录的事务ID
  • 7字节的回滚指针字段 DB_ROLL_PTR,如果在事务中这条记录被修改,指向这条记录的上一个版本

接下来就是除了 主键值为NULL 的列之外,其他列的真实数据,按照顺序从左到右依次排列

至于为什么不存储NULL值,原因很简单,就是为了节少空间,所有允许为NULL的列都会在行额外信息区的NULL值列表中进行标识 ,后面我们会详细详解,以上就是数据行对真实数据的存储方式。

在这里插入图片描述

🏳️‍🌈三、额外(管理)信息区包含了关于行的哪些信息?

在这里插入图片描述
额外信息区从右向左分别为: 头信息NuI值列表变长字段列表

🏳️‍🌈四、头信息区域包含了哪些信息?

在这里插入图片描述

  • 下一行地址偏移量: next_record 占16bit,通过这个信息将所有的行链接成一个单向链表
  • 行类型: record_type 占3bit,包括四种类型:
    • 0: 普通数据行
    • 1: 索引目录行
    • 2: 页内最小行 infimun
    • 3: 页内最大行 supremun
  • 行在整个页中的位置: heap_no 占13bit;
  • 分组的行数: n_owned 占4bit,只在该行是分组最后一行才有值,这样就可以快速查询行数,而不用一条条的累加了
  • B+树索引树每层最小值标记: min_rec_flag 占lbit,如果当前行的类型是目录行也就是 record_type=1,同时也是B+索引树某层的最小值,则会置为1,会在索引查询时用到,后面我们讲索引时再介绍
  • 删除标记: delete_mask1bit,从页中删除数据行时,并不会直接移除,而是修改这个删除标记为
  • 预留区: 占2bit

4.1 删除一行记录时在InnoDB内部执行了哪些操作?

从页中删除数据行时,并不会直接移除,而是修改 delete_mask 这个删除标记为1,并将 next_record 改为0,同时将 上一行的 next_record 指向后续的行,从而把该行从链表中断开

如果执行事务提交后,则这行的 next_record 指向一个被称为垃圾链表的区域,这个链表会被用在事务回滚中,后续在事务中详细介绍

🏳️‍🌈五、NuIl列表有啥作用? 列表中的值是什么?

  • 头信息区再向右就是 NULL值列表的可变区域,用来存储数据行中所有列允许为Null的值从而节省空间,具体的实现方式是,用1BIT的大小来表示行中某一列是否为空,这样空列就不需要记录在真实数据区域中了
  • 为每个没有定义 NOT NULL 约束也就是可以为NULL的列在NULL值列表中都安排了一个bit位,按列序号从小到大的顺序从右至左依序安排,这就是常说的逆序排列,NULL值列表最小1字节即8bit,如果没有那么多可以为NULL的列,则会用0补满8bit,如果为值为NULL的列超过8个,则新开辟1字节的空间,依此类推:
  • 如果某列为空,则NULL值列表中对应的bit设置为1,这样只用了一bit就存储了NULL列,非常节省空间

在这里插入图片描述

🏳️‍🌈六、变长字段列表有啥作用?列表中的值是什么?

查看编码集所占的字节数

mysql> show charset;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| binary   | Binary pseudo charset           | binary              |      1 |
| cp1250   | Windows Central European        | cp1250_general_ci   |      1 |
| cp1251   | Windows Cyrillic                | cp1251_general_ci   |      1 |
| cp1256   | Windows Arabic                  | cp1256_general_ci   |      1 |
| cp1257   | Windows Baltic                  | cp1257_general_ci   |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| cp852    | DOS Central European            | cp852_general_ci    |      1 |
| cp866    | DOS Russian                     | cp866_general_ci    |      1 |
| cp932    | SJIS for Windows Japanese       | cp932_japanese_ci   |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| eucjpms  | UJIS for Windows Japanese       | eucjpms_japanese_ci |      3 |
| euckr    | EUC-KR Korean                   | euckr_korean_ci     |      2 |
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |
| geostd8  | GEOSTD8 Georgian                | geostd8_general_ci  |      1 |
| greek    | ISO 8859-7 Greek                | greek_general_ci    |      1 |
| hebrew   | ISO 8859-8 Hebrew               | hebrew_general_ci   |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| keybcs2  | DOS Kamenicky Czech-Slovak      | keybcs2_general_ci  |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |
| koi8u    | KOI8-U Ukrainian                | koi8u_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |
| latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |
| latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
| latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |
| macce    | Mac Central European            | macce_general_ci    |      1 |
| macroman | Mac West European               | macroman_general_ci |      1 |
| sjis     | Shift-JIS Japanese              | sjis_japanese_ci    |      2 |
| swe7     | 7bit Swedish                    | swe7_swedish_ci     |      1 |
| tis620   | TIS620 Thai                     | tis620_thai_ci      |      1 |
| ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
| ujis     | EUC-JP Japanese                 | ujis_japanese_ci    |      3 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |
| utf8mb3  | UTF-8 Unicode                   | utf8mb3_general_ci  |      3 |
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_0900_ai_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.00 sec)

在这里插入图片描述

以下是⼀个建表的SQL语句

mysql> CREATE TABLE test_student (-> `id` bigint NOT NULL AUTO_INCREMENT,-> `sn` char(10) NOT NULL,-> `name` varchar(50) NOT NULL,-> `age` int NOT NULL,-> `mail` varchar(100) NOT NULL,-> `remark` varchar(255) NULL,-> PRIMARY KEY (`id`)-> );
Query OK, 0 rows affected (0.09 sec)
  • 行结构的最左侧是变长字段列表,也叫可变字段长度列表,在这个列表中记录了数据行中所有变长字段的实际长度,这样做的目的,是为了在真实数据区域,可以根据列的长度进行列与列之间的分割;
  • 需要记录的变长字段类型常见的有varchar、varbinary、text、blob,以及当使用了例如utf-8、gbk等变长字符集的char类型,当char类型的字节数可能超过768个字节时,比如使用utf8mb4字符集时定义了char(255),这个字段的最大字节数是4*255=1020
  • 每个变长字段分配1~2个字节来存放这些字段的真实大小,放置顺序也是按表中字段的顺序从右至左逆序排列;
mysql> CREATE TABLE test_varchar (-> `id` bigint NOT NULL AUTO_INCREMENT,-> `name` varchar(20000) NULL,-> PRIMARY KEY (`id`)-> );
ERROR 1074 (42000): Column length too big for column 'name' (max = 16383); use BLOB or TEXT instead
  • 2个字节最大可以表示65535个字节,按照最大长度字符串,比如 utf8mb4,一个字符占用最多4个字节计算,2个字节最多可以表示65535/4=16383个字符,列数据类型varchar的长度上限16383就是根据这个计算来的;
  • 需要特别说明的是,如果text、blob存储的内容过大,一个页已经不够放了,就会把这个列放入一个叫"溢出页"的独立空间中,在这个数据行对应的真实数据处,只使用20个字节来标记这个溢出页的位置信息

在这里插入图片描述

6.1 如何记录变长字段的实际长度?

不同的字符集在处理字符对应的最大字节长度不同,以如 ascii 最大1个字节, utf8mb3 最大3个字节,utf8mb4 最大4个字节,如下所示

| ascii   | US ASCII 	  | ascii_general_ci   | 1 |
| utf8mb3 | UTF-8 Unicode | utf8mb3_general_ci | 3 |
| utf8mb4 | UTF-8 Unicode | utf8mb4_0900_ai_ci | 4 |

当使用 varchar(M ) 指定一个字段的最大字符数时,该字段真实使用的字节数与建表时指定的字符集有关,如果指定的字符集单个字符最大占 w个字节,从理论上讲,该列最多使用的字节数 M *如果 M *W<= 255 则用一个字节记录这个变长字段的长度就足够了

如果 M *W> 255 可能分为两种情况,假设当前变长字段实现占用了L个字节:

6.2 读取长度时如何处理粘包问题?

  • 也就是说在读取变长字段长度时,如何确定读取一个字节还是两个字节?
  • 在任何时候都是先读一个字节,然后判断这个字节的高位是否为0,如果是0则表示当前用一个字节表示长度,如果是1则表示当前用两个字节表示长度
  • 为1时再读一个字节,然后合并在一起进行解析得到该字段真实的使用的字节数,而且第二个BIT位表示是否使用溢出页

默认数据页大小为16KB,数据页中一个数据行的大小最大为8KB

在这里插入图片描述

🏳️‍🌈七、其他的行格式与 DYNAMIC 有什么区别?

7.1 REDUNDANT 冗余格式

已被淘汰,之所以存在是为了与旧版本 MySQL兼容,不建议使用,这里不再讨论。

7.2 COMPRESSED 压缩格式

行结构与 DYNAMIC 完全相同,只是会对数据进行压缩,以减少对空间的占用。

7.3 COMPACT 紧凑格式

在结构上与 DYNAMIC 相同,只是对超长字段的处理上有些区别,它不会把所有超长数据都放在溢出页中,而是会在本行中保留前768个字节的数据,多出的部分放在溢出页中,溢出页的地址额外用20个字节表示,那么在本行的列中就会占用768+20个字节。


👥总结

在这里插入图片描述

本篇博文对 【MySQL】行结构详解:InnoDb支持格式、如何存储、头信息区域、Null列表、变长字段以及与其他格式的对比 做了一个较为详细的介绍,不知道对你有没有帮助呢

觉得博主写得还不错的三连支持下吧!会继续努力的~

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

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

相关文章

LabVIEW多通道并行数据存储系统

在工业自动化监测、航空航天测试、生物医学信号采集等领域&#xff0c;常常需要对多个传感器通道的数据进行同步采集&#xff0c;并根据后续分析需求以不同采样率保存特定通道组合。传统单线程数据存储方案难以满足实时性和资源利用效率的要求&#xff0c;因此设计一个高效的多…

【Linux系列】bash_profile 与 zshrc 的编辑与加载

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

针对Mkdocs部署到Githubpages加速访问速度的一些心得

加速网站访问的一些心得 在使用 MkDocs 构建网站时&#xff0c;为了提高访问速度&#xff0c;我们可以采取以下一些措施&#xff1a; 1. 优化图片 使用合适的图片格式&#xff0c;如 WebP、JPEG2000 等&#xff0c;减少图片文件大小&#xff0c;从而加快加载速度。 可以使用…

Mysql中切割字符串作为in的查询条件

问题&#xff1a;需要将一个字符串切割成数组作为in的查询条件&#xff0c;如&#xff1a; select * from table_1 where name in (select slit(names) from table_2 where id 3); names 返回的格式是’name1,name2,name3…,需要将name按照逗号切割作为in的查询条件&#xff1b…

云计算中的虚拟化:成本节省、可扩展性与灾难恢复的完美结合

云计算中虚拟化的 4 大优势 1. 成本效益 从本质上讲&#xff0c;虚拟化最大限度地减少了硬件蔓延。团队可以将多个虚拟机整合到单个物理主机上&#xff0c;而不是为每个工作负载部署单独的服务器。这大大减少了前期硬件投资和持续维护。 结果如何&#xff1f;更低的功耗、更低…

Linux : 多线程【线程概念】

Linux &#xff1a; 多线程【线程概念】 &#xff08;一&#xff09;线程概念线程是什么用户层的线程linux中PID与LWP的关系 (二) 进程地址空间页表(三) 线程总结线程的优点线程的缺点线程异常线程用途 &#xff08;一&#xff09;线程概念 线程是什么 在一个程序里的一个执行…

IDEA转战TREA AI IDE : springboot+maven+vue项目配置

一、trea下载安装 Trae官方网址&#xff1a; https://www.trae.com.cn/ Trae官方文档&#xff1a;https://docs.trae.com.cn/docs/what-is-trae?_langzh w3cschool&#xff1a; https://www.w3cschool.cn/traedocs/ai-settings.html 安装这里省略&#xff0c;正常安装即可。…

Java--图书管理系统(简易版)

目录 目录 前言 &#x1f514;1.library包 1.1 Book类 1.2 BookList类 &#x1f514;2.user包 2.1User类(父类) 2.2Admin(管理员) 2.3 NormalUser(普通用户) &#x1f514;3.Operation包 &#x1f550;3.1 IOperation接口 &#x1f551;3.2ListOperation(查看操作)…

深入浅出:Spring Boot 中 RestTemplate 的完整使用指南

在分布式系统开发中&#xff0c;服务间通信是常见需求。作为 Spring 框架的重要组件&#xff0c;RestTemplate 为开发者提供了简洁优雅的 HTTP 客户端解决方案。本文将从零开始讲解 RestTemplate 的核心用法&#xff0c;并附赠真实地图 API 对接案例。 一、环境准备 在 Spring…

大数据处理利器:Hadoop 入门指南

一、Hadoop 是什么&#xff1f;—— 分布式计算的基石 在大数据时代&#xff0c;处理海量数据需要强大的技术支撑&#xff0c;Hadoop 应运而生。Apache Hadoop 是一个开源的分布式计算框架&#xff0c;致力于为大规模数据集提供可靠、可扩展的分布式处理能力。其核心设计理念是…

685SJBH计量管理系统

摘 要 计量&#xff0c;在我国已有五千年的历史。计量的发展与社会进步联系在一起&#xff0c;它是人类文明的重要组成部分。它的发展经历了古典阶段、经典阶段和现代阶段。而企业的计量管理是对测量数据、测量过程和测量设备的管理。 本系统通过分析现有计量系统的业务逻辑…

从0到1构建前端监控系统:错误捕获、性能采集、用户体验全链路追踪实战指南SDK实现

目录 前言为什么要做前端监控前端监控目标稳定性用户体验业务 前端监控流程常见埋点方案代码埋点可视化埋点无痕埋点 创建项目第一步、创建monitor文件&#xff0c;cmd进入文件进行npm init -y 项目初始化第二步、创建src/index.js和src/index.html文件第三步、创建webpack.con…

前端浏览器判断设备类型的方法

前端浏览器判断设备类型的方法 在前端开发中&#xff0c;判断设备类型&#xff08;如手机、平板、桌面电脑&#xff09;有多种方法&#xff0c;以下是常用的几种方式&#xff1a; 1. 使用 User Agent 检测 通过 navigator.userAgent 获取用户代理字符串进行判断&#xff1a;…

MNIST 手写数字分类

转自我的个人博客: https://shar-pen.github.io/2025/05/04/torch-distributed-series/1.MNIST/ 基础的单卡训练 本笔记本演示了训练一个卷积神经网络&#xff08;CNN&#xff09;来对 MNIST 数据集中的手写数字进行分类的过程。工作流程包括&#xff1a; 数据准备&#xff…

数据库中的 Segment、Extent、Page、Row 详解

在关系型数据库的底层存储架构中&#xff0c;数据并不是随意写入磁盘&#xff0c;而是按照一定的结构分层管理的。理解这些存储单位对于优化数据库性能、理解 SQL 执行过程以及排查性能问题都具有重要意义。 我将从宏观到微观&#xff0c;依次介绍数据库存储中的四个核心概念&…

DAMA车轮图

DAMA车轮图是国际数据管理协会&#xff08;DAMA International&#xff09;提出的数据管理知识体系&#xff08;DMBOK&#xff09;的图形化表示&#xff0c;它以车轮&#xff08;同心圆&#xff09;的形式展示了数据管理的核心领域及其相互关系。以下是基于用户提供的关键词对D…

《QDebug 2025年4月》

一、Qt Widgets 问题交流 1. 二、Qt Quick 问题交流 1.QML单例动态创建的对象&#xff0c;访问外部id提示undefined 先定义一个窗口组件&#xff0c;打印外部的id&#xff1a; // MyWindow.qml import QtQuick 2.15 import QtQuick.Window 2.15Window {id: controlwidth: …

JS | 正则 · 常用正则表达式速查表

以下是前端开发中常用的正则表达式速查表&#xff0c;包含验证规则、用途说明与示例&#xff1a; &#x1f4cc; 常用正则表达式速查表 名称正则表达式描述 / 用途示例手机号/^1[3-9]\d{9}$/中国大陆手机号13812345678 ✅座机号/^0\d{2,3}-?\d{7,8}$/固定电话010-12345678 ✅…

系统思考:个人与团队成长

四年前&#xff0c;我交付的系统思考项目&#xff0c;今天学员的反馈依然深深触动了我。 我常常感叹&#xff0c;系统思考不仅仅是一场培训&#xff0c;更像是一场持续的“修炼”。在这条修炼之路上&#xff0c;最珍贵的&#xff0c;便是有志同道合的伙伴们一路同行&#xff0…