【大白话系列】MySQL 学习总结 之 COMPACT 行格式的设计原理

如果大家对我的 【大白话系列MySQL 学习总结系列 感兴趣的话,可以点击关注一波。

一、回顾

MySQL 学习总结系列至此已经第七节了。

从大方向:我们已经学习了 MySQL 的架构计、InnoDB 的架构计。

从较为深入的:我们已经学习了 rodo log 和 binlog 配合的两阶段提交协议,了解 缓冲池的设计原理和支持高并发、动态调整的管理机制。

下面,我们将介绍数据行格式:数据是以什么格式存储在数据页中的。

二、行存储格式

InnoDB 储存引擎支持有四种行储存格式:COMPACT、Redundant、Dynamic 和 COMPRESSED。

下面我们将重点介绍 COMPACT 行格式:

COMPACT 行存储格式大概类似这样:

变长字段的长度列表,null值列表,数据头,column01的值,column02的值,column0n的值......

ps:为了让磁盘空间得到最大的利用率,每个数据行都是紧紧地挨在一起的。

下面我们将详细介绍 COMPACT 行格式的各个知识点,当你学习完之后,你就晓得即使每行数据紧紧地挨在一起,MySQL 也能精准地将每行数据找出来~

三、变长字段如何存储? 1、变长字段的存储问题

我们都知道,varchar 类型是变长的,例如 varchar(50),那么这个字段值的长度范围:0 ~ 50 个字符。但是,不是每个字段值都刚好50个字符,肯定会有的长有的短。

那么,数据存储时,会按照字段定义时的最大长度来存储值吗?

必须不会的,如果都按照最大长度存储,当出现值不满 50个字符长度时,会浪费磁盘空间和内存空间。

为什么也浪费内存空间,数据不是存放在磁盘么?大家不会忘了缓冲池的作用了吧?哈哈,要记得缓冲池和磁盘数据交换的单位就是数据页~而数据行是存放在数据页中的~

2、变长字段长度列表

InnoDB 中,利用 变长字段长度列表 来解决上面的问题:

变长字段长度列表记录每一个变长字段值的长度,存储的长度是十六进制的。

如果有多个变长字段,那么变长字段长度列表是按逆序存储的。

下面用一个例子来描述一下变长字段长度列表的使用原理:

-- 表结构 create table test( c1 varchar(10) comment '字段1-变长', c2 varchar(5) comment '字段2-变长', c3 varchar(20) comment '字段3-变长', c4 char(1) comment '字段4-定长', c5 char(1) comment '字段5-定长' ) ENGINE=InnoDB; -- 一行数据 insert into test values('hello','ni','hao','a','a');

我们来算一下他们的长度(十六进制):

hello 的长度为5,十六进制为 0x05

ni 的长度为2,十六进制为 0x02

hao 的长度为3,十六进制为 0x03

那么,实际的存储格式是这样的:

0x03 0x02 0x05 null值列表 数据头 hello hi hao a a 四、NULL 值字段如何存储? 1、可为 NULL 字段的存储问题

定义为 default NULL 的字段,值可空可不空。那如果字段值为 NULL,数据行里是怎样存储的呢?是直接存储“NULL”字段吗?

我们分析一下:

如果是,那将会浪费磁盘空间,本来值就是 NULL 的,你现在给我搞了个四个字符大小的字符串。

如果不是,那怎么识别这个字段是否是 NULL 呢?

2、NULL值列表

InnoDB 中,利用 NULL值列表 来解决上面的问题:

NULL 值列表记录可为 NULL 的字段的情况。

用二进制bit位来标识字段值是否为 NULL。1为 NULL,0 不为 NULL。

如果有多个可为 NULL 的字段,那么 NULL 值列表也是按照逆序存储的。

而且 NULL 值列表的位数必须是 8bit 的N倍。例如:列表仅仅只有4个bit,则往高位补0,补到 8个bit。

下面用一个例子来描述一下 NULL 值列表 的使用原理:

-- 表结构 create table test( c1 varchar(10) not null comment '字段1-变长', c2 varchar(5) comment '字段2-变长', c3 char(1) comment '字段3-变长', c4 varchar(30) comment '字段4-定长', c5 varchar(50) comment '字段5-定长' ) ENGINE=InnoDB; -- 一行数据 insert into test values('howinfun',null,'m',null,'foshan');

算一下变长字段的长度:

howinfun 的长度为8,十六进制为 0x08

foshan 的长度为6,十六进制为 0x06

统计一下值为 NULL 的字段:

c2 字段为 NULL

c4 字段为 NULL

那么,实际的存储格式是这样的:

0x06 0x08 00000101 数据头 howinfun m foshan 3、采用 NULL值列表 和 直接存储“NULL”字符串相比,有多大的存储差距?

到此,我们就可以算一下这两种方案的存储差距有多大了。

一个字节 8个bit,NULL 值列表用二进制 bit 位来标识字段值是否为 NULL;那么就是说,标识8个字段才占用一个字节。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zywdjx.html