浅析InnoDB Record Header及page overflow(1)

简介: 浅析InnoDB Record Header及page overflow

前言

土人有土办法,利用innodb_ruby观测验证innodb page header及overflow临界点。

这是一篇封存了两年的文章,最近拿出来重新整理发布。

1、背景信息

1.1 InnoDB Diagrams项目

首先看一下Jeremy Cole、Davi Arnaut两位大神联合维护的牛逼项目:InnoDB Diagrams

在这个项目中,详细介绍了InnoDB引擎数据结构、日志结构,以及InnoDB内部的运行机制。

为了配合这个项目,二位大神还开发了一个InnoDB数据文件解析工具 innodb_ruby

1.2 InnoDB Record Header

InnoDB Diagrams项目中有一张图介绍了InnoDB record header是如何构成的

image.png


关于这些头信息的解释可见文章 The physical structure of records in InnoDB,本文不赘述。

简言之,记住几条关键规则

  • 一条记录的record header,至少是5字节
  • 对record header影响最大的是变长列数量,及其是否允许为NULL的属性

关于变长列

  • 每个变长列,如果列长度 <128 字节,则需要额外1字节
  • 每个变长列,如果列长度 >=128 字节,则需要额外2字节
  • 如果没有任何变长列,则无需这额外的1-2字节
  • 变长类型为char/varchar/text/blob等

同学们可能会诧异,char为什么也当做变长类型了?这是因为,当字符集非latin1时,最大存储长度可能会超过255字节,例如 char(65) utf8mb4 最长就可以存储260字节,此时在record header中需要用2字节来表示其长度,因此也被当做变长类型了

关于列允许为NULL

  • 每个列如果允许为NULL,则增加 1bit,不足8bit也需要额外1字节
  • 例如只有2个列允许为NULL,只需要2bit来表示,但也需要占用1字节

P.S,在InnoDB的存储结构里,从tablespace到segment,再到extent、page,还是file层面,总有各种必要的header或trailer信息需要消耗额外的字节数,不像MyISAM那么简单。

1.3 innodb_ruby项目

上面提过,innodb_ruby工具可以帮助我们进一步理解InnoDB引擎数据结构、日志结构。

该项目用ruby语言开发(大神真是任性,选了这个比较冷门的开发语言)。

特别提醒,该项目已经多年未更新,有些数据类型发生了变化(例如最经典的5.6之后时间日期类型),它解析的可能就不准确了,在我下面的实测案例中也证实了这点。因此,我还用到另外一个辅助工具 innblock

1.4 innblock工具

由八怪开发,用于扫描和分析InnoDB page,详见 innblock | InnoDB page观察利器


2、定义不同数据类型时的record header消耗

根据上面的理论,我们接下来计算并验证当表里有各种不同的数据类型时,分别需要多少额外字节。

关于测试环境

  1. MySQL版本:Percona Server 5.7.22-22
  2. 测试配套工具:innodb_ruby & innblock

特别提醒,测试表的字符集为utf8mb4

经过计算和验证,最终可以得到以下几条结论:

  1. 每条记录的record header(下面简称RH)基础是5字节(简写成 RH=5)
  2. 每当表中多一个列允许为NULL,则额外增加1bit,且不足8bit时也需要消耗1字节(同理,不足16bit时需要消耗2字节)
  3. 每当表中多一个最大定义存储长度不超过255字节的变长列(char/varchar)时,额外增加1字节
  4. 每当表中多一个最大定义存储长度超过255字节的变长列(char/varchar/text/blob)时,额外增加2字节

由此我们可以推断出以下几种场景所需的record header大小横屏观看,下同)

场景 表定义 行长度
(字节)
record header
(字节)
备注说明
1 id int not null
提醒:无显式主键
28 5 5(RH)
+6(TRX_ID)
+7(ROLL_PTR)
+6(ROW_ID)
+4(INT) = 28
2 id int
提醒:无显式主键,且未指定not null
29 6 6(允许null) + 6 +7 +6
+4
= 28
3 id int not null
primary key(id)
提醒:id列是显式主键
22 5 5 + 6 + 7
+4
= 22
4 id int not null,
c1 char(10),
primary key(id)
c1列只存储一个字符'a'
34 7 7(char+null)+
6 + 7
+ 4 + 10(c1)
= 34
5 id int not null,
c1 varchar(10),
primary key(id)
c1列只存储一个字符'a'
25 7 7(varchar+null) +
6 + 7
+ 4 + 1(c1)
= 25

更多的场景,详见下面这个汇总表格

image.png




            </div>
相关文章
|
云安全 人工智能 安全
|
存储 缓存 Java
LRU是什么?如何实现?
LRU(Least Recently Used)是一种常用的缓存淘汰策略,其核心思想是:如果一个数据在最近一段时间内没有被访问到,那么在未来它被访问的可能性也很小。因此,当缓存满了的时候,最久未使用的数据会被淘汰
|
传感器 人工智能 5G
|
缓存 JavaScript 前端开发
Node.js模块化的基本概念和分类及使用方法
Node.js模块化的基本概念和分类及使用方法
280 0
|
Ubuntu Linux Shell
10-21|在linux我如果修改了时间,什么命令可以恢复正确啊
10-21|在linux我如果修改了时间,什么命令可以恢复正确啊
绘梦相似,AIGC图生图:相似图像生成模型魔搭社区开源体验
日常我们在艺术创作和产品设计中,需要多张风格相似的图片
|
定位技术 C++ Python
ArcMap软件卡在加载界面且闪退无法打开的多种解决办法
ArcMap软件卡在加载界面且闪退无法打开的多种解决办法
947 1
|
存储 机器学习/深度学习 数据挖掘
时序数据库 TDengine 与高级分析软件 Seeq 集成,来看看操作手册
通过 TDengine Java connector,Seeq 可以轻松支持查询 TDengine 提供的时序数据,并提供数据展现、分析、预测等功能。本文将对此进行介绍。
580 2
|
数据可视化 小程序 前端开发
【iVX】十五分钟制作一款小游戏,iVX真有怎么神?
【iVX】十五分钟制作一款小游戏,iVX真有怎么神?
514 0
|
存储 NoSQL JavaScript
Linux下快速搭建YApi接口管理平台
目录 一、序言 二、安装Node 1、安装nvm 2、使用兼容的Node版本 二、安装MongoDB 1、下载MongoDB 2、配置MongoDB 三、安装YApi 四、安装PM2管理Node服务 五、登录YApi后台
Linux下快速搭建YApi接口管理平台