mysql原理--InnoDB记录结构
1.InnoDB行格式
我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为 行格式 或者 记录格式 。
设计 InnoDB 存储引擎的大叔们到现在为止设计了4种不同类型的 行格式 ,分别是 Compact 、 Redundant 、Dynamic 和 Compressed 行格式。
1.1.指定行格式的语法
我们可以在创建或修改表的语句中指定 行格式 :
CREATE TABLE 表名 (列的信息) ROW_FORMAT=行格式名称;
ALTER TABLE 表名 ROW_FORMAT=行格式名称;
1.2.实例解析
我们后续基于下述实例进行说明。
mysql> CREATE TABLE record_format_demo (-> c1 VARCHAR(10),-> c2 VARCHAR(10) NOT NULL,-> c3 CHAR(10),-> c4 VARCHAR(10)-> ) CHARSET=ascii ROW_FORMAT=COMPACT;
mysql> INSERT INTO record_format_demo(c1, c2, c3, c4) VALUES('aaaa', 'bbb', 'cc', 'd'), ('eeee', 'fff', NULL, NULL);
1.3.COMPACT行格式

1.3.1.记录的额外信息
(1). 变长字段长度列表
我们知道 MySQL 支持一些变长的数据类型,比如 VARCHAR(M) 、 VARBINARY(M) 、各种 TEXT 类型,各种 BLOB 类型,我们也可以把拥有这些数据类型的列称为 变长字段 ,变长字段中存储多少字节的数据是不固定的,所以我们在存储真实数据的时候需要顺便把这些数据占用的字节数也存起来,这样才不至于把 MySQL 服务器搞懵,所以这些变长字段占用的存储空间分为两部分:
a. 真正的数据内容
b. 占用的字节数
在 Compact 行格式中,把所有变长字段的真实数据占用的字节长度都存放在记录的开头部位,从而形成一个变长字段长度列表,各变长字段数据占用的字节数按照列的顺序逆序存放。
我们拿 record_format_demo 表中的第一条记录来举个例子。因为 record_format_demo 表的 c1 、 c2 、 c4 列都是 VARCHAR(10) 类型的,也就是变长的数据类型,所以这三个列的值的长度都需要保存在记录开头处,因为 record_format_demo 表中的各个列都使用的是 ascii 字符集,所以每个字符只需要1个字节来进行编码,来看一下第一条记录各变长字段内容的长度:

由于第一行记录中 c1 、 c2 、 c4 列中的字符串都比较短,也就是说内容占用的字节数比较小,用1个字节就可以表示,但是如果变长列的内容占用的字节数比较多,可能就需要用2个字节来表示。具体用1个还是2个字节来表示真实数据占用的字节数, InnoDB 有它的一套规则,我们首先声明一下 W 、 M 和 L 的意思:
(1). 字符集中表示一个字符最多需要使用的字节数为 W。
(2). 对于变长类型 VARCHAR(M) 来说,这种类型表示能存储最多 M 个字符(注意是字符不是字节),所以这个类型能表示的字符串最多占用的字节数就是 M×W 。
(3). 它实际存储的字符串占用的字节数是 L 。
确定使用1个字节还是2个字节表示真正字符串占用的字节数的规则就是这样:
(1). 如果 M×W <= 255 ,那么使用1个字节来表示真正字符串占用的字节数。
(2). 如果 M×W > 255 ,则分为两种情况:
a. 如果 L <= 127 ,则用1个字节来表示真正字符串占用的字节数。
b. 如果 L > 127 ,则用2个字节来表示真正字符串占用的字节数。
当用两字节存储占用字节数时,首先MySQL采用小端存储,然后两字节的数值的最高位固定为1。所以,可存储的最大值为: 2 15 − 1 2^{15} - 1 215−1。
假设要存储一个占据257字节的变长字段,数值为0x101,结合小端存储,最高位固定为1。所以,MySQL存储上先是0x01,再是0x81。
当可变字段实际尺寸很长,以至于超过 2 15 − 1 2^{15} - 1 215−1时,MySQL有溢出页机制来处理。
(2).NULL值列表
我们知道表中的某些列可能存储 NULL 值,如果把这些 NULL 值都放到 记录的真实数据 中存储会很占地方,所以 Compact 行格式把这些值为 NULL 的列统一管理起来,存储到 NULL 值列表中,它的处理过程是这样的:
a. 首先统计表中允许存储 NULL 的列有哪些。
主键列、被 NOT NULL 修饰的列都是不可以存储 NULL 值的。
b. 如果表中没有允许存储 NULL 的列,则 NULL值列表 也不存在了,否则将每个允许存储 NULL 的列对应一个二进制位,二进制位按照列的顺序逆序排列,二进制位表示的意义如下:
b.1.二进制位的值为 1 时,代表该列的值为 NULL 。
b.2.二进制位的值为 0 时,代表该列的值不为 NULL 。
因为表 record_format_demo 有3个值允许为 NULL 的列,所以这3个列和二进制位的对应关系就是这样:

c. MySQL 规定 NULL值列表 必须用整数个字节的位表示,如果使用的二进制位个数不是整数个字节,则在字节的高位补 0 。
表 record_format_demo 只有3个值允许为 NULL 的列,对应3个二进制位,不足一个字节,所以在字节的高位补 0 ,效果就是这样:

上述实例中插入两行后,存储信息如下:

(3).记录头信息
是由固定的 5 个字节组成。 5 个字节也就是 40 个二进制位,不同的位代表不同的意思,如图:

1.3.2.记录的真实数据
对于 record_format_demo 表来说, 记录的真实数据 除了 c1 、 c2 、 c3 、 c4 这几个我们自己定义的列的数据以外, MySQL 会为每个记录默认的添加一些列(也称为 隐藏列 ),具体的列如下:
| 列名 | 是否必须 | 占用空间 | 描述 |
|---|---|---|---|
| DB_ROW_ID | 否 | 6 字节 | 行ID,唯一标识一条记录 |
| DB_TRX_ID | 是 | 6 字节 | 事务ID |
| DB_ROLL_PTR | 是 | 7 字节 | 回滚指针 |
这里需要提一下 InnoDB 表对主键的生成策略:优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个 Unique 键作为主键,如果表中连 Unique 键都没有定义的话,则 InnoDB 会为表默认添加一个名为 DB_ROW_ID 的隐藏列作为主键。所以我们从上表中可以看出:InnoDB存储引擎会为每条记录都添加 DB_TRX_ID 和 DB_ROLL_PTR 这两个列,但是 DB_ROW_ID 是可选的(在没有自定义主键以及Unique键的情况下才会添加该列)。
上述实例插入两行的实际内容:

1.3.3.CHAR(M)列的存储格式
如果采用变长的字符集(也就是表示一个字符需要的字节数不确定,比如gbk 表示一个字符要1~2个字节、 utf8 表示一个字符要1~3个字节等)的话,此时即使列的类型是形如 CHAR(M) 类型时,也视为变长字段。相应的变长字段长度列表会包含此列尺寸信息。
变长字符集的 CHAR(M) 类型的列要求至少占用 M 个字节,而 VARCHAR(M) 却没有这个要求。比方说对于使用 utf8 字符集的 CHAR(10) 的列来说,该列存储的数据字节长度的范围是10~30个字节。即使我们向该列中存储一个空字符串也会占用 10 个字节。
2.行溢出数据
2.1.VARCHAR(M)最多能存储的数据
MySQL内部限制用户表一行存储中,剔除行中类型BLOB,TEXT类型字段,剔除隐藏列,记录头后剩余部分累计尺寸不可超过65535。因此,VARCHAR(M)中 M 受此限制影响可设置的最大值是有限制的。
2.2.记录中的数据太多产生的溢出
MySQL 中磁盘和内存交互的基本单位是 页 ,也就是说 MySQL 是以 页 为基本单位来管理存储空间的,我们的记录都会被分配到某个 页 中存储。而一个页的大小一般是 16KB ,也就是 16384 字节,而一个 VARCHAR(M) 类型的列就最多可以存储 65532 个字节,这样就可能造成一个页存放不了一条记录的尴尬情况。
在 Compact 和 Reduntant 行格式中,对于占用存储空间非常大的列,在 记录的真实数据 处只会存储该列的一部分数据,把剩余的数据分散存储在几个其他的页中,然后 记录的真实数据 处用20个字节存储指向这些页的地址(当然这20个字节中还包括这些分散在其他页面中的数据的占用的字节数),从而可以找到剩余数据所在的页,
如图所示:

从图中可以看出来,对于 Compact 和 Reduntant 行格式来说,如果某一列中的数据非常多的话,在本记录的真实数据处只会存储该列的前 768 个字节的数据和一个指向其他页的地址,然后把剩下的数据存放到其他页中,这个过程也叫做 行溢出 ,存储超出 768 字节的那些页面也被称为 溢出页 。
最后需要注意的是,不只是 VARCHAR(M) 类型的列,其他的 TEXT、BLOB 类型的列在存储数据非常多的时候也会发生 行溢出 。
2.3.行溢出的临界点
MySQL 中规定一个页中至少存放两行记录。当无法在一个页中完成两行记录的完整存储时,会通过页溢出来完成记录信息存储。
2.4.理解MySQL磁盘和内存交互以页面为单位
上述实例表对应一个磁盘上的文件record_format_demo.ibd,就是说上述文件内容按16KB切割。每个切割出的内容构成一个页。每个页按其性质有特定的页内数据组织方式。
相关文章:
mysql原理--InnoDB记录结构
1.InnoDB行格式 我们平时是以记录为单位来向表中插入数据的,这些记录在磁盘上的存放方式也被称为 行格式 或者 记录格式 。 设计 InnoDB 存储引擎的大叔们到现在为止设计了4种不同类型的 行格式 ,分别是 Compact 、 Redundant 、Dynamic 和 Compressed 行…...
ES6基础语法
目录 一、解构 数组解构 对象解构 字符串解构 数值解构 布尔值解构 二、箭头函数 和普通函数区别? 三、拓展运算符 ... 一、解构 给右侧值匹配对应的变量 等号两侧模式一定要匹配 数组解构 /*** 解构:从数组或者对象中提取值,给变量进行赋值操作就…...
java8 常用code
文章目录 前言一、lambda1. 排序1.1 按照对象属性排序:1.2 字符串List排序:1.3 数据库排序jpa 2. 聚合2.1 基本聚合(返回对象list)2.2 多字段组合聚合(直接返回对象list数量) 二、基础语法2.1 List2.1.1 数…...
docker 镜像管理
搜索镜像:这种方法只能用于官方镜像库搜索基于 centos 操作系统的镜像# docker search centos 按星级搜索镜像: 查找 star 数至少为 100 的镜像,默认不加 s 选项找出所有相关 ubuntu 镜像: # docker search ubun…...
Jira 中如何修改时间为绝对时间
问题描述 在使用Jira的时候,有一些时间显示的是相对时间,如:2天前,3个小时前等,有些用户不习惯这样的显示方式,希望使用绝对的时间格式,如:2022年2月22日 22:22 应该怎样修改 解…...
班级查分软件制作教程:老师必备技能!
首先,你需要选择一个合适的软件平台来制作班级查分软件。推荐使用群发成绩,因为它是一个功能强大且易于使用的在线查询系统,可以帮助你快速高效地制作班级查分软件。 在制作班级查分软件之前,你需要准备好学生的成绩数据。这可以…...
Linux 的性能调优的思路
Linux操作系统是一个开源产品,也是一个开源软件的实践和应用平台,在这个平台下有无数的开源软件支撑,我们常见的apache、tomcat、mysql等。 开源软件的最大理念是自由、开放,那么Linux作为一个开源平台,最终要实现的是…...
如何通过webdriver禁用浏览器定位功能
今天碰到一个小问题,在使用了代理ip的情况下访问某些站点,但是还是显示本地的ip地址,这个是什么问题呢,原来是谷歌浏览器默认打开了定位功能 那么问题来了,如何在使用webdriver的时候关闭浏览器的定位功能呢࿱…...
网卡bonding绑定
目录 一、概念 1、概述: 二、实验 1、绑定案例: 一、概念 1、概述: 将多个物理网卡进行排列组合,形成逻辑网卡,网卡的高可用 绑定模式 mode0(平衡负载模式):平时两块网卡均工…...
flink运行报Exception in thread “main“ java.lang.IllegalStateException
问题描述 运行flink程序时报异常,异常信息如下: Exception in thread "main" java.lang.IllegalStateException: No ExecutorFactory found to execute the application.at org.apache.flink.core.execution.DefaultExecutorServiceLoader.g…...
易点易动设备管理系统--提升设备备品备件管理效率的工具
设备备品备件管理是市场推广人员关注的重要问题之一。为了帮助市场推广人员提升设备备品备件管理效率,易点易动设备管理系统应运而生。本文将详细介绍易点易动设备管理系统的功能和优势,以及如何借助该系统提高设备备品备件管理效率,提升企业…...
第二十一章——网络通信
一.网络程序设计基础 1.局域网与互联网 2.网络协议 1.IP协议 IP是Internet Protocol的简称,是一种网络协议。 1.1 TCP/IP层次结构 2.TCP与UDP协议 TCP可保证数据从一端送至另一端时,能够确实送达,而且抵达的数据的排列顺序和送出时的顺序相…...
Siemens-NXUG二次开发-打开与关闭prt文件[Python UF][20231206]
Siemens-NXUG二次开发-打开与关闭prt文件[Python UF][20231206] 1.python uf函数1.1 NXOpen.UF.Part.Open1.2 NXOpen.UF.Part.LoadStatus1.3 NXOpen.UF.Part.Close1.4 NXOpen.UF.Part.AskUnits 2.示例代码3.运行结果3.1 内部模式3.2 外部模式 1.python uf函数 1.1 NXOpen.UF.P…...
2015年五一杯数学建模C题生态文明建设评价问题解题全过程文档及程序
2015年五一杯数学建模 C题 生态文明建设评价问题 原题再现 随着我国经济的迅速发展,生态文明越来越重要,生态文明建设被提到了一个前所未有的高度。党的十八大报告明确提出要大力推进生态文明建设,报告指出“建设生态文明,是关系…...
java:slf4j、log4j、log4j2、logback日志框架的区别与示例
文章目录 背景SLF4J - 简单日志门面:Log4j - 强大而古老的日志框架:Log4j2 - Log4j的升级版:Logback - Log4j的继任者:比较Springboot集成slf4j、log4j2参考 背景 在Java开发中,日志记录是一个不可或缺的组成部分。为了满足不同的需求,Java社区涌现出多…...
Mysql学习查缺补漏----02 mysql之DCL 数据控制语言
查看数据库里都有哪些用户。 使用root任何一个用户都可以登录。 本机登录。 也可以这样登录其他的机器。 、 修改user表。 刷新权限: 现在我们看到了只有本机才能登陆。 我们这样就可以限制这个mysql指定某台服务器登录。 详解忘记密码以及如何修改用户密码 我们…...
【Flink基础】-- 延迟数据的处理
目录 一、关于延迟的一些概念 1、什么是延迟? 2、什么导致互联网延迟?...
通过keepalived+nginx实现 k8s apiserver节点高可用
一、环境准备 K8s 主机配置: 配置: 4Gib 内存/4vCPU/60G 硬盘 网络:机器相互可以通信 k8s 实验环境网络规划: podSubnet(pod 网段) 10.244.0.0/16 serviceSubnet(service 网段): 1…...
JavaScript 数组
JavaScript 数组 用来存储一系列相关数据的一种数据类型 创建数组 字面量方式 ----- [1,2,3,4,5,6];实例化构造函数 ----- new Array(1,2,3,4,5,6);组成数组的元素可以是任意的数据类型包括数组本身; new Array(n): n 表示数组的长度 内容操作 获取(查…...
【数据结构】二叉树的实现
目录 1. 前言2. 二叉树的实现2.1 创建一棵树2.2 前序遍历2.2.1 分析2.2.2 代码实现2.2.3 递归展开图 2.3 中序遍历2.3.1 分析2.3.2 代码实现2.3.3 递归展开图 2.4 后序遍历2.4.1 分析2.4.2 代码实现2.4.3 递归展开图 2.5 求节点个数2.5.1 分析2.5.2 代码实现 2.6 求叶子节点个数…...
AD21实战:3种方法搞定Keepout和机械层互转,最后一种能救急
AD21实战:3种高效解决Keepout与机械层互转难题的方法 在PCB设计过程中,Keepout层和机械层的正确使用与转换是确保设计准确性的关键环节。许多工程师都遇到过这样的困境:当设计文件中包含复杂图形元素时,简单的层切换或属性批量修…...
管人对账累垮人?巨有科技智慧市集系统一招减负
从城市商圈到景区古镇,从乡村田园到文创园区,各类市集遍地开花,但管理难题始终是制约行业发展的最大瓶颈。人工登记杂乱、对账结算繁琐、现场管控滞后、数据完全空白,一场中型市集就要耗费大量人力物力,大型市集更是纠…...
联想M920x黑苹果终极指南:从零构建完美macOS系统
联想M920x黑苹果终极指南:从零构建完美macOS系统 【免费下载链接】M920x-Hackintosh-EFI Hackintosh Opencore EFIs for M920x 项目地址: https://gitcode.com/gh_mirrors/m9/M920x-Hackintosh-EFI 你是否想让联想M920x这款紧凑型主机运行macOS系统ÿ…...
新手避坑指南:用Prometheus+PX4+ROS在Gazebo里复现无人机追踪小车(保姆级流程)
新手避坑指南:用PrometheusPX4ROS在Gazebo里复现无人机追踪小车(保姆级流程) 当第一次接触无人机仿真开发时,很多人会被复杂的工具链和晦涩的错误信息劝退。本文将手把手带你完成从零搭建仿真环境到实现视觉追踪的全过程ÿ…...
VS Code终端切换全攻略:从PowerShell到CMD的保姆级教程(含常见问题解决)
VS Code终端切换全攻略:从PowerShell到CMD的保姆级教程(含常见问题解决) 在开发者的日常工作中,终端是不可或缺的工具。VS Code作为最受欢迎的代码编辑器之一,其内置终端功能强大且高度可定制。然而,许多开…...
终极指南:用VizTracer可视化Python代码执行的完整教程
终极指南:用VizTracer可视化Python代码执行的完整教程 【免费下载链接】viztracer VizTracer is a low-overhead logging/debugging/profiling tool that can trace and visualize your python code execution. 项目地址: https://gitcode.com/gh_mirrors/vi/vizt…...
别再手动改配置了!用Flutter的--dart-define实现开发/测试/生产环境一键切换
Flutter多环境配置实战:用--dart-define打造全链路自动化工作流 每次切换环境都要手动修改十几个配置项?还在为不同环境的API地址、应用图标和包名管理头疼?是时候告别这种低效的开发方式了。作为一位经历过无数个深夜调试环境的Flutter开发者…...
深入对比:在Vivado中设计异步复位、同步复位和带使能D触发器的实战差异与选型建议
深入对比:在Vivado中设计异步复位、同步复位和带使能D触发器的实战差异与选型建议 当你在设计一个状态机或数据流水线时,是否曾为选择哪种D触发器而犹豫不决?异步复位、同步复位还是带使能的D触发器,每种设计都有其独特的应用场景…...
python-flask-djangol框架的婚恋相亲交友网站
目录技术选型与框架对比核心功能模块设计数据库模型示例(Django ORM)安全防护措施部署方案开发路线图项目技术支持源码获取详细视频演示 :文章底部获取博主联系方式!同行可合作技术选型与框架对比 Flask:轻量级框架&a…...
Word自动编号的隐藏玩法:用题注和交叉引用,打造能“自我修复”的智能文档
Word文档工程化:构建自动编号与交叉引用的智能系统 在技术文档撰写过程中,最令人头疼的莫过于图表编号的维护。当你在200页的文档中插入新图表时,手动编号意味着要逐个修改后续所有编号和引用——这种痛苦只有经历过的人才懂。但很少有人意识…...
