【InnoDB 存储引擎】InnoDB 存储引擎的行格式,有 Compact、Redundant、Dynamic 等行格式还有它们配套实验(理论篇)

news2024/12/25 14:12:54

文章目录

  • 1 InnoDB 行记录格式(理论)
    • 1.1 Redundant 行记录格式
    • 1.2 Compact 行记录格式(重点)
    • 1.3 行溢出数据
    • 1.4 Compressed 和 Dynamic 行记录格式
    • 1.5 CHAR 的行结构存储
  • 2 参考资料

1 InnoDB 行记录格式(理论)

在 InnoDB 存储引擎中,记录是以行的形式存储的,这意味着页中保存着表中一行行的数据。用户可以通过命令 SHOW TABLE STATUS LIKE 'table_name' 来查看当前表使用的行格式,其中 row_format 属性表示当前所使用的行记录结构类型。如:

在 InnoDB 存储引擎发展历史中出现了多种行格式,如:Redundant、Compact、Dynamic 等

1.1 Redundant 行记录格式

前言:有配套的实验

Redundan 是旧的行记录格式,了解即可。Redundant 行记录采用如下图所示的方式存储:

字段长度偏移列表:

不同于 Compact 行记录格式,Redundant 行记录格式的首部是一个字段长度偏移列表,同样是按照列的顺序逆序放置的。若列的长度小于255字节,用1字节表示;若大于255字节,用2字节表示

举个栗子

-- 1、创建一个表
create table t1 (
    a varchar(10),
    b varchar(10),
    c char(10),
    d varchar(10)
) ENGINE = innodb charset=latin1 ROW_FORMAT = Redundant;
-- 2、插入数据
insert into select a,bb,bb,ccc;

从 t1.ibd 文件中捞出的字段长度偏移列表为[23 20 16 14 13 0c 06],调整顺序为[06 0c 13 14 16 20 23],表示的含义是第1个字段的长度是6,第2个字段的长度是6(06 + 06 = 0c),第3个字段的长度是7(0c + 07 = 13),第4个字段的长度是1(13 + 01 = 14),第5个字段的长度是2(14 + 02 = 16),第6个字段的长度是10(16 + 0a = 20),第7个字段的长度是3(20 + 03 = 23)。为什么会多出3个字段我们只定义了4个字段现有有7个,这3个字段是隐藏字段

第1个字段:即 rowid,确实是占用6个字节

第2个字段:即 TranactionID,确实是占用6个字节

第3个字段:即 roll pointer,确实是占用7个字节

第4个字段:即字符’a’,确实是占用1个字节

第5个字段:即字符’bb’,确实是占用2个字节

第6个字段:即字符’bb’,但是是 char(10) 类型,确实是占用10个字节

第7个字段:即字符’ccc’,确实是占用3个字节

特别的,在 Redundant 中 NULL 的长度是通过符号位表示的,即 16 进制的 80,换算成二进制是 10000000,这是个符号位表示不了任何长度,所以表示 NULL 就很合适了

记录头信息:

不同于Compact行记录格式,Redundant行记录格式的记录头占用6字节(48位),每位的含义如下表

名 称大小(bit)描 述
()1未知
()1未知
deleted_flag1该行是否已被删除
min_rcc_flag1为1,如果该记录是预先被定义为最小的记录
n_owned3该记录拥有的记录数
heap_no13索引堆中该条记录的索引号
n_fields10记录中列的数量
lbyte_offs__flag1偏移列表为1字节还是2字节
next_record16页中下一条记录(rowid)的相对位置(相对谁:相对本页的地址)
Total48

比较重要的 2 个项已经用黑体标出

n_owned:

跟 Compact 格式一样,不赘述

next_record:

页中下一条的相对位置。相对本页的地址,而 Compact 相对的本记录的偏移地址

具体列的数据:

记录头信息的后面就是行的具体数据了

1.2 Compact 行记录格式(重点)

前言:有配套的实验

Compact 行记录格式其设计目标是高效地存储数据。简单来说,一个页中存放的行数据越多,其性能就越高。下图显示了 Compact 行记录的存储方式:

变长字段长度列表:

Compact行记录格式的首部是一个变长字段长度列表,该列表是指非NULL的字段,并且是按照列的顺序逆序处置的。变长字段就是指字段类型如 VARCHAR 等这些可以动态扩展的列,其长度有如下的 2 条规则:

  • 若列的长度小于 255( 2 8 2^8 28) 字节,用 1 字节表示其长度即可
  • 若列的长度大于 255 字节,用 2 字节表示其长度即可

变长字段的长度最大不可以超过2字节,这是因在MySQL数据库中VARCHAR类型的最大长度限制为65535

举个栗子

-- 1、创建一个表
create table t1 (
    a varchar(10),
    b varchar(10),
    c char(10),
    d varchar(10)
) ENGINE = innodb charset=latin1 ROW_FORMAT =COMPACT;
-- 2、插入数据
insert into select a,bb,ccc,dddd;

那么插入的第一条记录的变长字段列表为[04,02,01],分别对应dddd,bb,a的长度(逆序排可变长度列)

NULL 标志位列表:

变长字段之后的第二个部分是NULL标志位列表,列表表明了该行的所有字段中哪些字段是 NULL,二进制位值为1则该字段为NULL(是从二进制列表右往左数的)。如:

十六进制的 NULL 标志位列表为 07 时,转换为二进制 00000111 ,表明该表的字段不超过 8 个字段,且第 1、2、3 个字段均为 NULL

十六进制的 NULL 标志位列表为 01 07 时,转换为二进制为 00000001 00000111 ,表明该表的字段个数大于 8 个小于 16 个,且第 1、2、3、9 个字段均为 NULL

记录头通用信息:

记录头通用信息一般包括 4 个小部分,依顺序分别是:Record Header(记录头)RowID(主键)、TranactionID(事务 ID 列)、Roll Pointer(回滚指针列)

对于用户插入的记录一般 4 部分都有,而对于系统预设的一些记录一般只有 Record Header 其他则没有

重点看 Record Header 和 RowID

1、Record Header

记录头固定占用 5 个字节(40位),每位的含义见下表:

名 称大小(bit)描 述
()1未知
()1未知
dcleted_flag1该行是否已被删除
min_rcc_flag1为1,如果该记录是预先被定义为最小的记录
n_owned4该记录拥有的记录数
heap_no13索引堆中该条记录的排序记录
recordtype3记录该行记录的类型,000表示普通,001表示B+树的结点指针。。。
next_record16页中下一条记录的相对位置(相对谁:相对本记录的 rowid 地址)
Total40

记录头信息(Record Header)的最后两个字节就是next_record,next_record代表下一个记录的偏移量,即当前记录的位置(特指 rowid 的地址)加上next_record的偏移量就是下一条行记录的起时位置(特指 rowid 的地址),所以在页的内部,实则上也是通过一种链表的形式来串连各条行记录的

比较重要的 2 个项已经用黑体标出

n_owned:

该项表明该记录拥有多少个记录。**解释:**InnoDB 为了加快记录的查找速度,采用了稀疏目录的管理方式,多个记录对应一个稀疏目录条目,如查询 id = 5 时先把页加载到内存中,先确定该记录对应哪一个稀疏目录条目,随后定位到条目的第一个记录再依次遍历链表直到找到 id = 5 的记录。所以 n_owned=4 就表示 4 个记录共用一个稀疏目录条目

next_record:

该项代表下一个记录的偏移量。即当前记录的位置(特指 rowid 的地址)加上next_record的偏移量就是下一条行记录的起时位置(特指 rowid 的地址),所以在页的内部,实则上也是通过一种链表的形式来串连各条行记录的

Compact 格式下一行的相对地址相对的是本记录的 rowid 的地址

2、RowID

该字段是表示行记录的主键,如果给表指定了主键就用指定的,如果没有则使用系统自动生成的

该字段的长度视情况而定,如果指定主键为 int 类型则占用 4 个字节,为 varchar 则可能更多;如果系统自动生成则固定为 6 个字节

3、TranactionID

事务 ID 列,占用 6 个字节

4、Roll Pointer

回滚指针列,占用 7 个字节

具体列的数据:

记录头信息的后面就是行的具体数据了

1.3 行溢出数据

1、行溢出是一种现象,是指数据存不下,在存储大对象(BLOB、TEXT)列类型时会很容易发生,它们的数据不存储在普通的页中(普通页只有 16KB 存不下),而是存储在特殊的页中(Uncompress BLOB页)

2、存储 varchar 列类型也有可能发生行溢出(毕竟 varchar 的最大长度可以支持 65535,普通页存不下)

3、BLOB 也并不一定存放在特殊页中,varcahr 也不一定不存放在特殊页中

4、到底是不是存在在特殊的页中,主要看一行数据的长度是不是太长了(一般的,如果一页中能存储下 2 行就存放在普通页。如果一页中只能存下一行数据那么页完全退化为链表)

执行如下几个测试观察然后理解 mysql 对 varchar 的长度和行长度是有限制的

-- 按照最大值设置 varchar
CREATE TABLE test (
    a VARCHAR(65532)
)CHARSET=latin1 ENGINE=InnoDB;
-- 慢慢缩小 varchar 的大小
CREATE TABLE test (
    a VARCHAR(65532)
)CHARSET=latin1 ENGINE=InnoDB;
-- 改成 GBK
CREATE TABLE test (
    a VARCHAR(65532)
) CHARSET=GBK ENGINE=InnoDB;
-- 改成 UTF8
CREATE TABLE test (
    a VARCHAR(65532)
) CHARSET=utf8 ENGINE=InnoDB;
-- 测试 mysql 对行长度的限制
CREATE TABLE test2 (
    a VARCHAR(22000),
    b VARCHAR(22000),
    c VARCHAR(22000)
)CHARSET=latin1 ENGINE=InnoDB;

实验结果:

1、varchar 列类型中的长度指的是字节的长度,不是字符的长度,一般不要把 varchar 的长度设置的太大

2、每一行的数据大小也是有限制的,太长了一个普通页都存不下都要用特殊也,那怎么玩

1.4 Compressed 和 Dynamic 行记录格式

这 2 种是新的行记录格式,新的两种记录格式对于存放在BLOB中的数据采用了完全的行溢出的方式

1.5 CHAR 的行结构存储

前言:有配套的实验

通常理解VARCHAR是存储变长长度的字符类型,CHAR是存储固定长度的字符类型。在前面,用户已经了解行结构的内部的存储,并可以发现每行的变长字段长度的列表都没有存储CHAR类型的长度

但是,值得注意的是之前给出的两个例子中的字符集都是单字节的latinl格式。CHAR(N)中的N指的是字符的长度,而不是之前版本的字节长度。 也就说在不同的字符集下,CHAR类型列内部存储的可能不是定长的数据。在不同的字符集下,char(N) 的字节长度是不一样的,如在 charset=gbk 下 char(N) 最多占用 2N 个字节,在 charset=latin1 下 char(N) 占用 N 个字节,在 charset=utf8 下 char(N) 最多占用 3N 个字节

char(N) 指的是 字符的长度,而 varchar(N) 指的是字节的长度

2 参考资料

官网:https://dev.mysql.com/doc/refman/8.0/en/innodb-row-format.html

InnoDB 行记录格式(实验):我的另外文章:《15.10 InnoDB 行记录格式(实验,重要)》

书籍:《InnoDB 存储引擎》,该书电子版练习作者无套路免费下载


传送门: 保姆式Spring5源码解析

欢迎与作者一起交流技术和工作生活

联系作者

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

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

相关文章

什么是数据一致性

什么是数据一致性 数据一致性这个单词在平常开发中,或者各种文章中都能经常看见,我们常常听见什么东西数据不一致了,造成了一定的损失,赶快修复一下。但是很多同学对一致性具体代表什么意思,他有什么作用依然不是很了解…

车载软件架构 —— 闲聊几句AUTOSAR OS(八)

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 没有人关注你。也无需有人关注你。你必须承认自己的价值,你不能站在他人的角度来反对自己。人生在世,最怕的就是把别人的眼光当成自己生活的唯一标…

Overleaf 集成git出现authentification failed 的解决方法

Overleaf 集成git遇到的问题和解决办法 需求背景:使用git 将overleaf 项目克隆到本地硬盘上工作,像写代码一样管理论文版本。 问题描述:直接使用overleaf提供的git clone xxxx 会出现authentication failed for xxxxx (见下图) …

C++中的继承/虚继承原理

C中的继承 文章目录 C中的继承1.继承的概念和定义1.1 继承定义1.12 继承关系和访问限定符2.基类和派生类对象的复制转换3.继承中的作用域4.派生类的默认成员函数继承与友元 6.**继承与静态成员****复杂的菱形继承及菱形虚拟继承**7.虚继承解决数据冗余和二义性的原理 1.继承的概…

git 技术点整理

1.git安装 1.1官网下载 Git 安装详情见https://www.cnblogs.com/liuwenwu9527/p/11688323.html 1.2配置 2.git基本概念 2.1本地 工作区(Working Directory):就是你在电脑里能看到的目录。说人话就是idea直接能看到的这部分纯代码区域。(不含 .git…

基于51单片机的太阳追光系统设计

本实例是基于51单片机的太阳追光系统,主要硬件由51单片机最小系统,四路光敏感应电路,ADC0832转换电路、LED指示灯电路、X轴与Y轴步进电机构成。 设计功能 1.四路光敏感应电路:四路光敏电阻分别感应上、下、左、右四个方向的光强…

两组表单看懂MySQL的多表查询

第一组表单信息 1、查询每个部门的所属员工 mysql> SELECT name,GROUP_CONCAT(ename) persons-> FROM dept3 d-> LEFT JOIN emp3 e-> ON d.deptno e.dept_id-> GROUP BY d.deptno-> UNION -> SELECT name,GROUP_CONCAT(ename) persons-> FROM dept3 …

代码随想录算法训练营第六十天| 84.柱状图中最大的矩形

柱状图中最大的矩形 题目链接: 力扣 假设以柱子1(指值为1的柱子)为基准,柱子1的左侧没有比柱子1矮的元素,所以柱子1可以无限像左边扩展,柱子1的右侧也没有比柱子1矮的元素,所以柱子1可以无限向…

用OpenCV进行图像分割--进阶篇

1. 引言 大家好,我的图像处理爱好者们! 在上一篇幅中,我们简单介绍了图像分割领域中的基础知识,包含基于固定阈值的分割和基于OSTU的分割算法。这一次,我们将通过介绍基于色度的分割来进一步巩固大家的基础知识。 闲…

如何提升问卷数据的有效性?

问卷调查法是收集数据的宝贵工具,可以为商业、社会科学和医疗保健等众多领域的决策过程提供真实可靠的数据信息。然而,问卷数据的准确性和可靠性是影响最终结论的关键因素,而他们取决于问卷设计和数据收集过程的质量。在本文中,我…

Coggle 30 Days of ML(23年7月)任务三:使用TFIDF提取文本特征

Coggle 30 Days of ML(23年7月)任务三:使用TFIDF提取文本特征 任务三:使用TFIDF提取文本特征 说明:在这个任务中,需要使用Sklearn库中的TFIDF技术来提取文本特征,将文本转化为可供机器学习算法…

数分面试题:赛马问题

问题一: 25匹马,一个赛道,每次可以跑5匹马,在没有计时器的情况下,怎么用最小的比赛次数知道最快的前三名 关键点:通过前面的比赛,排除掉没有悬念的马(能确定有3匹马比它快的&#…

Iptables与Firewalld

Iptables防火墙 介绍 iptables和netfilter是一套Linux防火墙工具,共同合作完成系统防护工作。iptables 是一个包过滤防火墙,可以对包进行封装、过滤、重定向或者网络地址转换、地址伪装、透明代理、访问控制、连接跟踪等功能,iptables是一个…

4.6 x64dbg 内存扫描与查壳实现

LyScript 插件中默认提供了多种内存特征扫描函数,每一种扫描函数用法各不相同,在使用扫描函数时应首先搞清楚不同函数之间的差异,本章内容将分别详细介绍每一种内存扫描函数是如何灵活运用,并实现一种内存查壳脚本,可快…

Linux常用命令——exec命令

在线Linux命令查询工具 exec 调用并执行指定的命令 补充说明 exec命令用于调用并执行指令的命令。exec命令通常用在shell脚本程序中,可以调用其他的命令。如果在当前终端中使用命令,则当指定的命令执行完毕后会立即退出终端。 语法 exec(选项)(参数…

计算机组成原理32位MIPS CPU设计实验(指令译码器电路设计 、时序发生器状态机设计、时序发生器输出函数、硬布线控制器)

实验四 32位MIPS CPU设计实验 这次实验是32位MIPS CPU设计实验(单总线CPU-定长指令周期-3级时序),在头歌当中一共需要我们进行六道题的测试,分别为MIPS指令译码器设计,定长指令周期(时序发生FSM设计,时序发…

数据结构05:树与二叉树[C++][哈夫曼树HuffmanTree]

图源:文心一言 考研笔记整理6k字,小白友好、代码可跑,请小伙伴放心食用~~🥝🥝 第1版:查资料、画导图、画配图~🧩🧩 参考用书:王道考研《2024年 数据结构考研复习指导》…

一纸文书之MySQL的回忆录

MySQL要点学习:你可以在简历上说熟悉MySQL 什么是数据库?什么是数据库管理系统?什么是MySQL?什么是SQL?数据库数据库管理系统:SQL:结构化查询语言三者之间的关系 安装MySQL数据库管理系统MySQL常…

数据增强之裁剪、翻转与旋转

文章和代码已经归档至【Github仓库:https://github.com/timerring/dive-into-AI 】或者公众号【AIShareLab】回复 pytorch教程 也可获取。 文章目录 数据增强 Data Augmentation裁剪Croptransforms.CenterCroptransforms.RandomCroptransforms.RandomResizedCroptra…

【雕爷学编程】Arduino动手做(153)---2.4寸TFT液晶触摸屏模块7

37款传感器与执行器的提法,在网络上广泛流传,其实Arduino能够兼容的传感器模块肯定是不止这37种的。鉴于本人手头积累了一些传感器和执行器模块,依照实践出真知(一定要动手做)的理念,以学习和交流为目的&am…