0
点赞
收藏
分享

微信扫一扫

MySQL原理 - InnoDB引擎 - 行记录存储 - Off-page 列

8052cf60ff5c 2022-05-06 阅读 85

Redundant 中 off-page 列处理


对于 Redundant 行格式中比较长的列,只有前 768 字节会被存储在数据行上,剩下的数据会被放入其他页。我们来看一个实例,运行以下 SQL,创建一个测试表,插入测试数据:

drop table if exists long_column_test;

CREATE TABLE long_column_test (

large_content varchar(32768) DEFAULT NULL

) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=REDUNDANT;

##长度为 768 字节

insert into long_column_test values (repeat(“az”, 384));

##长度为 8100 字节

insert into long_column_test values (repeat(“az”, 4050));

##长度为 32768 字节

insert into long_column_test values (repeat(“az”, 16384));

我们使用 64 进制编码器查看表文件 long_column_test.ibd,可以看到第一条数据是一条正常的数据,其存储和之前我们讲的 Redundant 列存储一样,没有特殊的:

image

所有字段长度列表(8字节,4列,一个数据列,三个隐藏列):03 13(768+7+6+6),00 13(7+6+6),00 0c(6+6), 00 06( 《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》无偿开源 威信搜索公众号【编程进阶路】 6)

记录头(6字节):00 00 10 08 03 ac

隐藏列 DB_ROW_ID(6字节):00 00 00 00 02 22

隐藏列 DB_TRX_ID(6字节):00 00 00 00 58 b7

隐藏列 DB_ROLL_PTR(7字节):82 00 00 01 0c 01 10

数据列 large_content(768字节):61 7a …

对于第二行,我们发现这一行的 large_content 列的数据并没有完全存储在这一行,而是一部分存储在这一行,另一部分存储在了其他地方,这种列就被称为 off-page 列,存储到的其他地方被称为 overflow 页,其结构如下:

image

首先是数据列

所有字段长度列表(8字节,4列,一个数据列,三个隐藏列):43 27(第一字节的头两位不代表长度,最高位还是标记字段是否为NULL,第二位标记这条记录是否在同一页,由于不为 NULL,所以最高位为 0,由于存在 overflow 页所以不在同一页,所以第二位为1,后面的 3 27 代表长度,即 20+768+7+6+6),00 13(7+6+6),00 0c(6+6), 00 06(6)

记录头(6字节):00 00 10 08 03 ac

隐藏列 DB_ROW_ID(6字节):00 00 00 00 02 22

隐藏列 DB_TRX_ID(6字节):00 00 00 00 58 b7

隐藏列 DB_ROLL_PTR(7字节):82 00 00 01 0c 01 10

数据列 large_content(768字节):61 7a …

指向剩余数据所在地址的指针(20字节):00 00 05 23 00 00 00 05 00 00 00 01 00 00 00 00 00 00 1c a4

对于 off-page 列,列数据末尾会存在指向剩余数据所在地址的指针,这个指针占用 20 字节,它的结构是:

image

然后是列剩下的数据存储到的 overflow 页

数据列 large_content(剩余的 7332 字节):61 7a …

当字段再长一些呢,超过一页内数据的限制的时候呢?我们来看第三行数据结构:

image

可以看出,过长的数据列,会以链表链接的形式存储在 overflow 页上。

由此可见 Redundant 行格式中,off-page 的结构其实是:

image

这样我们会联想到三个问题:

  1. 什么时候列会变成 off-page 列?

  2. 什么时候 overflow 页会分成一个个链表节点存储?

  3. 对于哪些列类型会这么存储?

1. 什么时候列会变成 off-page 列?

首先我们知道一点,innodb 引擎的页大小默认是 16KB,也就是 16384 字节,而且 innodb 的数据是按页加载的。然后,组织 innoDB 引擎数据的数据结构是 B+ 树。扫描 B+ 树寻找数据,也是一页一页加载搜索的。如果一页内能包含的数据行越多,那么很明显,搜索效率越高。但是如果一页中只有一条数据,那么这个 B+ 树其实和链表的效率差不多了。所以,为了效率,需要保证一页内至少有两条数据。所以有:

2∗行数据大小<16384→行数据大小<81922∗行数据大小<16384→行数据大小<8192

同时,一行数据并不是只有列数据,还有隐藏列,记录头,列长度列表等等,并且,innoDB 页也有自己的一些元数据(占用 132 字节,我们在以后的章节会详细分析),在这里我们拿 long_column_test 作为例子,则有:

page元数据大小+2∗‘long_column_test‘行数据大小<16384→132+2∗(字段长度列表长度+记录头长度+三个隐藏列长度+large_content长度)<16384page元数据大小+2∗‘long_column_test‘行数据大小<16384→132+2∗(字段长度列表长度+记录头长度+三个隐藏列长度+large_content长度)<16384

可以推导出:

large_content长度<8093large_content长度<8093

在实际使用中,可能不止一列数据比较长。还有,由于数据不存储在行数据一起,搜索读取效率会比较低,所以,redundant 行格式会尽可能不把列变为 off-page 列,并尽量少的将列变为 off-page 列。

2. 什么时候 overflow 页会分成一个个链表节点存储?

overflow 页和表数据不同,不通过 B+ 树组织数据,同时不会做复杂搜索,它就是一个链表。所以我们只要保证数据大小不超过一页即可,即:

overflow页数据节点大小<16384overflow页数据节点大小<16384

这个数据节点也是有一些额外信息的,同时,页也是有自己的额外信息的,这些会在之后的文章中看到。所以,真正承载的数据大小,会需要刨除这些额外信息,也就是小于 16384。如果不够,就会分成多页存储,这些节点会通过一个链表链接起来。

3. 对于哪些列类型会这么存储?

对于可变长度字段,例如 varchar,varbinary,text,blob 等,会利用这种机制存储。对于定长字段,例如 char,如果超长,也会像 varchar 一样存储,在这种情况下,char 末尾就不会填充空白字符了。但是这种情况不常见,char 最长只能 255 个字符,字符编码必须是大于三字节的时候,才会大于 768,例如 uf8mb4 并且每个字符都是大于 3 字节的字符。

Compact 中 off-page 列处理


举报

相关推荐

0 条评论