mysql之Innodb的Infimum和Supremum与用户记录的二三事

一、前言

在上一篇中,学习了页的结构和行记录信息在页中的与伪记录的关系。这一篇中先验证一下伪记录与行记录的关系。下面开始~


二、构建基础实验环境

1.创建表

 CREATE TABLE `compact_record_page` (
  `col0` int(11) NOT NULL,
  `col1` varchar(10) DEFAULT NULL,
  `col2` char(5) DEFAULT NULL,
  `col3` int(11) DEFAULT NULL,
  `col4` varchar(5) DEFAULT NULL,
  `col5` varchar(15) NOT NULL,
  PRIMARY KEY (`col0`)
) ENGINE=InnoDB DEFAULT CHARSET=ascii ROW_FORMAT=COMPACT 

2.插入数据

INSERT INTO mysqlstudy.compact_record_page (col0, col1, col2, col3, col4, col5) VALUES (1, 'aa', 'aaa', 10, null, 'aaa');
INSERT INTO mysqlstudy.compact_record_page (col0, col1, col2, col3, col4, col5) VALUES (2, 'bb', 'bbb', 10, null, 'bbb');
INSERT INTO mysqlstudy.compact_record_page (col0, col1, col2, col3, col4, col5) VALUES (3, 'cc', 'ccc', 10, null, 'ccc');
INSERT INTO mysqlstudy.compact_record_page (col0, col1, col2, col3, col4, col5) VALUES (4, 'dd', 'ddd', 10, null, 'ddd');

3.从ibd中提取行记录信息

由于csdn不支持文件格式,所以ibd文件就不上传了。
mysql之Innodb的Infimum和Supremum与用户记录的二三事_第1张图片

三、开始解析

1.寻找伪记录Infimum

根据Infimum的69 6e 66 69 6d 75 6d 00 往前找5个字节构成Infimum伪记录信息得到以下16进制字节信息

总共13个字节 其中5个字节的头信息  还有8个字节表示Infimum单词的ascii字符数组 最后一个00 表示补位
01 00 02 00 1d 
69 6e66 696d 756d 00

基于下图进行伪记录头信息解析
mysql之Innodb的Infimum和Supremum与用户记录的二三事_第2张图片
01 对应的2进制 0000 0001 其中第一个预留位为0,第二个预留位为0,第三个delete_flag为0,第四个min_rec_flag为0,第五位到第8位共四个比特位表示n_owned,且数值为1,意味这Infimum是分组里的老大,且组内记录只有一条。那说明Infimum自成一组。

00 02 对应的2进制 0000 0000 0000 0010 取前13个比特位 0000 0000 0000 0 表示heap_no的值。说明Infimum伪记录的在页内行记录的相对位置为0。取后3个比特位 010 表示record_type,值为2,刚好与上图Infimum记录的类型相符。

00 1d 对应的2进制为 0000 0000 0001 1101 ,取这16个比特位标识next_record,其值为29。表示当前位置到下一条记录真实数据的位置为29

69 6e 66 69 6d 75 6d 00 总共8个字节,最后一个字节是补位。前七个字节分表表示Infimum中的每个字符。

2.寻找伪记录Supremum

从Infimum记录往后找13个字节得到Supremum

五个字节的头信息 + 8个字节的Supremum单词ascii字符
05 00 0b 00 00 73 75 70 72 65 6d 75 6d

05 对应的二进制为 0000 0101 ,形同Infimum分析,这里只有n_owned不同,且数值为5,意味着Supremum是分组内的大佬,且管理着四条插入的用户记录,所以组内共5条记录。

00 0b 对应的二进制为 0000 0000 0000 1011 ,取前13位比特位作为head_no,对应的值为1,表示在页内的相对位置为1。 取后3个比特位作为record_type,对应值为3,刚好与Supremum记录类型的值一致。

00 00 对应的二进制为 0000 0000 0000 0000 ,取这16个比特位作为next_record,表示当前记录的真是数据到下一条记录的真是数据的距离为0。也就是没有下一条记录了。

3.寻找第一条记录

第一条记录中,所有字符串值都为a,a对应的ascii码为61。
根据Infimum中的next_record=29,我们需要往后找29个字节。
其中Infimum的内容占8个字节,Supremum占13个字节,那么还剩8个字节。
那么就是可变字符长度列表+null值列表+固定头信息

INSERT INTO mysqlstudy.compact_record_page 
(col0, col1, col2, col3, col4, col5) VALUES 
(1, 'aa', 'aaa', 10, null, 'aaa');

03 col5可变字符长度
02 col1 可变字符长度
082进制为 0000 0100 。当前总共有四个可为null的列,从后往前分别是 col4 col3 col2 col1,
基于null值列表的倒序排列规则,从后往前col3的值对应于1的位置,也就是标识为1了。至于前面40,则是补位。
00 00 10 00 27  固定头信息(稍后会在下面详细解析)
80 00 00 01 00 00   事务ID
00 26 7c 66 d6 00 00   回滚指针
01 37 01 10         主键内容(特殊格式,后面讲解)
61 61               col1的值
61 61 61 20 20      col2的值 固定长度字符,实际长度不足时,在后面补空格(ascii 2080 00 00 0a         col3的值 int型表示方法 
61 61 61            col5的值 

头信息解析
头信息的16进制格式:
00 00 10 00 27

头信息的二进制格式:
0000 0000 0000 0000 0001 0 000 0000 0000 0010 0111

头信息同Infimum和Supremum进行解析
预留位 0
预留位 0
delete_flag 0
min_rec_flag 0

n_ownd 0000 这是跟Infimum和Supremum的地方,用户记录可以作为组老大也可以不作为组老大,这个是跟一个页类用户记录数和页切分有关的,会在后面的内容进行讲解。

head_no 0000 0000 0001 0 转为10进制数值为2,表示在堆内位置为2

record_type 000 转为10进制数值为0,代表普通记录

next_record 0010 0111 转为10进制数值为39 ,下一条记录的真实数据起始位置为第39个字节

非真实数据长度:2(变长字段列表)+1(null值列表)+5(头信息) = 8个字节
真实数据总共占据 6(事务ID)+7(回滚指针) + 4(col0)+2(col1)+5(col2)+4(col3)+3(col5) = 31个字节

Infimum的next_record计算为:Infimum的真实数据8字节+Supremum整个记录的13字节+第一条记录的非真实数据长度8字节 = 8+13+8 = 29 字节

刚好与Infimum的next_record 一致

4.寻找第二条记录

03  col5 可变字符长度
02  col1 可变字符长度
08  null值列表 (同第一条记录)
00 00 18 00 27  固定头部信息(稍后下面进行解析)
80 00 00 02 00 00 事务ID
00 26 7c 67 d7 00 00 回滚指针
01 38 01 10     主键内容(特殊格式,后面讲解)
62 62           col1的值
62 62 62 20 20  col2的值
80 00 00 0a     col3的值
62 62 62        vol5的值

解析头部信息

00 00 18 00 27

0000 0000 0000 0000 0001 1000 0000 0000 0010 0100

省略部分雷同头信息

head_no 0000 0000 0001 1 标识堆内位置为3

record_type 000 标识为普通记录

next_record 0010 0100 标识下一条记录的真实数据起始位置相对于当前记录真实数据起始位置的距离为39

第二条记录长度计算

非真实数据长度:2(变长字段列表)+1(null值列表)+5(头信息) = 8个字节

真实数据总共占据 6(事务ID)+7(回滚指针) + 4(col0)+2(col1)+5(col2)+4(col3)+3(col5) = 31个字节

第一条记录的真实数据长度+第二条记录的非真实数据长度 = 31+8 = 39

由此验证了关于next_record 的相关规则。

5.寻找第三条记录

根据第一条和第二条记录,这里便不再进行解析,直接解析头信息的区别
03 02  可变长度列表
08 null值列表
00 00 20 00 27 头信息
80 00 00 03 00 00 事务ID
00 26 7c 6c da 00 00  回滚指针
01 3a 01 10  主键
6363              col1
63 63 63 20 20    col2
80 00 00 0a       col3
63 63 63          col5

第三条和前面两条基本一致所以会省略一些信息。只列出不同点

头信息解析:

00 00 20 00 27

0000 0000 0000 0000 0010 0000 0000 0000 0010 0111

这里只有head_no 不一样为 0000 0000 0010 0 数值为4 ,表示在页内相对记录的第四条

6.寻找第四条记录

根据第一条和第二条记录,这里便不再进行解析,直接解析头信息的区别
03 02
08
00 00 28 ff 7b
80 00 00 04 00 00
00 26 7c 6d db 00 00
01 b2 01 10
64 64
64 64 64 20 20
80 00 00 0a
64 64 64

这里由于是最后一条真实用户记录,所以头信息会跟前面的记录有所不同

解析头信息:

00 00 28 ff 7b

0000 0000 0000 0000 0010 1000 1111 1111 0111 1011

head_no 0000 0000 0010 1 对应数值5 堆内为5

record_type 000 标识普通记录

next_record 1111 1111 0111 1011 第一位为1时,我们通常会想到整型的负数在计算机中存储的形式为补码,这里涉及到原码,反码 ,补码。

我们来计算一下

补码:

1111 1111 0111 1011

反码:负数的补码-1 得到反码

1111 1111 0111 1010

原码:除符号位以外进行取反

1000 0000 1000 0101

原码的十进制为133

往前找到Supremum的真实数据起始位置:

第四条非真实:8字节

第三条:39 字节

第二条:39 字节

第一条: 39 字节

Supremum真实数据字节:8

共计133字节

而最后一条next_record实际值为133字节

四、小结

这里验证了关于伪记录的位置和用户记录的关系。其中对行结构的读取方式和next_record的计算方式进行了深入验证。下一篇将验证一下删除一条记录后,伪记录与行记录将发生什么变化~

你可能感兴趣的:(mysql,mysql,innodb,Infimum,Supremum,next_record)