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

而如果用字符串的方式来存储,而一个"NULL"字符串足足用了四个字节(英文一个字符等于一个字节,中文一个字符等于两个字节),那么同样的8个字段就需要36个字节了。

这差距是非常明显的!

五、数据头

COMPACT 行格式中,除了 变长字段长度列表 和 NULL 值列表,就到数据头了。

数据头的大小为 40 个bit位。

下面介绍 40个 bit 分别都有什么信息。

名称 大小 (bit) 描述
预留位1   1   没有使用  
预留位2   1   没有使用  
delete_mask   1   标记该记录是否被删除  
min_rec_mask   1   B+树里每一层的非叶子节点里的最小值都有这个标记  
n_owned   4   表示当前记录拥有的记录数  
heap_no   13   表示当前记录在记录堆的位置信息  
record_type   3   标识当前记录的类型:0代表的是普通类型,1代表的是B+树非叶子节点,2代表的是最小值数据,3代表的是最大值数据。  
next_record   16   表示下一条记录的相对位置  

那么,我们看一下,加上数据头的实际存储:

0x06 0x08 00000101 0000000000000000000010000000000000011001 howinfun m foshan 六、一行数据在磁盘是如何存储的 1、字符集编码

上面,我们已经介绍了 COMPACT 行格式了,那么一行数据真正是如何存储的?

我们都知道,在建库和建表时,都可以指定字符集编码。所以,数据都会经过数据库指定的字符集编码后,再进行存储的。

下面用一个例子来描述一下使用原理:

-- 表结构 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' ) -- 一行数据 insert into test values('howinfun',null,'m',null,'foshan');

假设编码后:

howinfun 编码后:61616161

m 编码后:62

foshan编码后:636363

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

0x06 0x08 00000101 0000000000000000000010000000000000011001 61616161 62 636363 2、隐藏字段

除了变长字段长度列表、NULL值列表、40个bit位的数据头和真实数据,其实还包含了一些隐藏字段:

DB_ROW_ID 字段:如果我们没有指定主键和unique key唯一索引的时候,他就内部自动加一个ROW_ID作为主键。

DB_TRX_ID 字段:事务 ID,标识这是哪个事务更新的数据

DB_ROLL_PTR 字段:回滚指针,用来进行事务回滚的

加上隐藏字段后,上面的例子的实际存储可能就是:

0x06 0x08 00000101 0000000000000000000010000000000000011001 00000000094C(DB_ROW_ID)00000000032D(DB_TRX_ID) EA000010078E(DB_ROL_PTR) 616161 636320 6262626262

ps:括号里只是做说明用的,事实是不存在的。

3、行溢出问题

数据页的默认大小是 16kb,但是某些字段的值可以远远大于 16kb。

例如变长字段类型 varchar(N):N 最大可为 65532(65kb),这就远远大于 16kb。

当然了,还有 text 和 blog 字段,这些都是大字段,都可以超过 16kb。

如果一行数据的大小超过了 16kb,就会出现行溢出的现象。

怎么解决?

当一行数据超了 16kb,会在超了大小的那个字段中,可能仅仅包含他的一部分数据,然后同时包含一个20个字节的指针,指向存储了这行数据超了的部分的其他数据页。

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

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