浅析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>
相关文章
|
6月前
|
存储 安全 关系型数据库
【InnoDB引擎如何管理Page页】
【InnoDB引擎如何管理Page页】
|
存储 NoSQL 关系型数据库
浅析InnoDB Record Header及page overflow(2)
浅析InnoDB Record Header及page overflow
|
存储 NoSQL 关系型数据库
浅析InnoDB Record Header及page overflow(2)
浅析InnoDB Record Header及page overflow
|
存储 关系型数据库 MySQL
浅析InnoDB Record Header及page overflow(1)
浅析InnoDB Record Header及page overflow
浅析InnoDB Record Header及page overflow(1)
|
1月前
|
存储 关系型数据库 MySQL
MySQL InnoDB数据存储结构
MySQL InnoDB数据存储结构
|
1月前
|
存储 缓存 关系型数据库
MySQL的varchar水真的太深了——InnoDB记录存储结构
varchar(M) 能存多少个字符,为什么提示最大16383?innodb怎么知道varchar真正有多长?记录为NULL,innodb如何处理?某个列数据占用的字节数非常多怎么办?影响每行实际可用空间的因素有哪些?本篇围绕innodb默认行格式dynamic来说说原理。
835 6
MySQL的varchar水真的太深了——InnoDB记录存储结构
|
3月前
|
存储 SQL 关系型数据库
系统设计场景题—MySQL使用InnoDB,通过二级索引查第K大的数,时间复杂度是多少?
系统设计场景题—MySQL使用InnoDB,通过二级索引查第K大的数,时间复杂度是多少?
47 1
系统设计场景题—MySQL使用InnoDB,通过二级索引查第K大的数,时间复杂度是多少?
|
3月前
|
存储 SQL 关系型数据库
Mysql系列-4.Mysql存储引擎-InnoDB(下)
Mysql系列-4.Mysql存储引擎-InnoDB
49 0
|
2月前
|
存储 缓存 关系型数据库
MySQL - 存储引擎MyISAM和Innodb
MySQL - 存储引擎MyISAM和Innodb