教你如何使用UE观察InnoDB Page结构-爱可生

导读:

贴心tips:在阅读本文之前建议先快速阅读一下《InnoDB Page结构详解》

点击了解

创建表结构,插入三条数据

<code>root@mysqldb 11:01:  [xucl]> show create table t\G*************************** 1. row ***************************       Table: tCreate Table: CREATE TABLE `t` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `c1` varchar(10) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb41 row in set (0.00 sec)root@mysqldb 11:01:  [xucl]> select * from t;+----+------+| id | c1   |+----+------+|  1 | a    ||  2 | NULL ||  3 | a    |+----+------+3 rows in set (0.00 sec)/<code>

用ue打开t.ibd文件,为什么用ue呢,我觉得ue是观察16进制文件最好的工具了,hexdump由于大小端的原因,看起来太费劲了。

教你如何使用UE观察InnoDB Page结构-爱可生

page no=3是第一个数据页,那么我们从0000c000到00010000之间就是我们这个数据页所有的数据了。

整理一下得到如下:

<code>        0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  fc000    38 AD C1 F5 00 00 00 03 FF FF FF FF FF FF FF FFc010    00 00 00 11 4E 07 B2 CA 45 BF 00 00 00 00 00 00c020    00 00 00 00 04 D2 00 02 00 C1 80 05 00 00 00 00c030    00 AF 00 02 00 02 00 03 00 00 00 00 00 00 00 00c040    00 00 00 00 00 00 00 00 08 48 00 00 04 D2 00 00c050    00 02 00 F2 00 00 04 D2 00 00 00 02 00 32 01 00c060    02 00 1C 69 6E 66 69 6D 75 6D 00 02 00 0B 00 00c070    73 75 70 72 65 6D 75 6D 01 00 00 00 10 00 18 80c080    00 00 01 00 00 00 0C 81 E7 B5 00 00 00 05 01 10c090    61 01 00 00 18 00 18 80 00 00 02 00 00 00 0C 81c0a0    E8 B6 00 00 00 05 01 10 01 00 00 00 20 FF C1 80 c0b0    00 00 03 00 00 00 0C 81 E9 B7 00 00 00 05 01 10c0c0    61................................fff0    00 00 00 00 00 70 00 63 38 AD C1 F5 4E 07 B2 CA/<code>

先看File Header 38字节

  • 38 AD C1 F5:4字节,表示数据页的checksum值
  • 00 00 00 03:4字节,表示页的偏移量,这个页也就是page no = 3的页
  • FF FF FF FF:4字节,前一个页的指针,因为我们现在只有一个page,所以为FF FF FF FF
  • FF FF FF FF:4字节,下一个页的指针,因为我们现在只有一个page,所以为FF FF FF FF
  • 00 00 00 11 4E 07 B2 CA:8字节,page的LSN
  • 45 BF:2字节,页的类型,表示这个page是数据页
  • 00 00 00 00 00 00 00 00:8字节,独立表空间该值都为0
  • 00 00 04 D2:4字节,表示SPACE ID,表空间ID可以在informa shema下的INNODBSYSTABLESPACES表查到

再看Page Header 56字节

  • PAGENDIR_SLOTS(2字节):00 02表示只有2个slot,每个slot占用2个字节,结束偏移量为0ff7,那么开始偏移量就为0ff4,也就是00 70 00 63,倒序存储
  • PAGEHEAPTOP(2字节):00 C1,0000c000 + c1 = c0c1,即最后一条记录往后一个位置
  • PAGENHEAP(2字节):80 05,表示page内共有5条记录,?
  • PAGE_FREE(2字节):00 00,表示可重用空间首地址
  • PAGE_GARBBAGE(2字节):00 00:表示删除的记录字节数
  • PAGELASTINSERT(2字节):00 AF:最后插入位置,C000+00AF= C0AF
  • PAGEDIRECTION(2字节):00 02:表示PAGENO_DIRECTION
  • PAGENDIRECTION(2字节):00 02,一个方向连续插入记录的数量
  • PAGENRECS(2字节):00 03,页中包含的记录数,注意不包含最大最小记录
  • PAGEMAXTRX_ID(8字节):00 00 00 00 00 00 00 00,修改当前页的最大事务ID,注意该值仅在Secondary Index中定义
  • PAGE_LEVEL(2字节):00 00,B树的高度
  • PAGEINDEXID(8字节):00 00 00 00 00 00 08 48,索引ID,该值可以在informationschema下的INNODBSYS_INDEXES查到
  • PAGEBTRSEG_LEAF(10字节):00 00 04 D2 00 00 00 02 00 F2:B+树数据页非叶节点所在段的segment header。注意该值仅在B+数的Root页中定义
  • PAGEBTRSEG_TOP(10字节):00 00 04 D2 00 00 00 02 00 32:B+树数据页所在段的segment header。注意该值仅在B+数的Root页中定义

最大最小虚拟记录:

infimum:01 00 02 00 1C 69 6E 66 69 6D 75 6D 00

  • Record header:01 00 02 00 1C(其中1c表示下一条记录的偏移量)
  • 行记录:69 6E 66 69 6D 75 6D 00 可以计算出来的第一条用户记录的偏移量就是c063+1c=0c7f

supremum:02 00 0B 00 00 73 75 70 72 65 6D 75 6D

  • Record header:02 00 0B 00 00
  • 行记录:73 75 70 72 65 6D 75 6D

用户记录:

为了表示得更加清楚,我把两条虚拟记录位置也标注出来

<code>c063->99infimum:01 00 02 00 1C |69 6E 66 69 6D 75 6D 00/<code>
<code>c070->112supremum:02 00 0B 00 00 73 75 70 72 65 6D 75 6D/<code>

record1:

<code>c07f>12701 00 00 00 10 00 18 |80 00 00 01 |00 00 00 0C 81 E7 |B5 00 00 00 05 01 10 |61/<code>
  • record header:01 00 00 00 10 00 18
  • 01表示变长字段,因为我们这里c1字段是变长字段,且占用空间小于255字节,占用1字节
  • 00表示null bit map,因为我们这里c1字段不为空,因此为00
  • 00 00 10 ->00000000 00000000 00010000,0000info flag,0000 record owned, 00000000 00010表示heap no=2
  • 00 18表示下条记录的相对偏移量
  • 80 00 00 01:主键ID,4字节,没有指明无符号,因此是80 xxx开头
  • 00 00 00 0C 81 E7:trx_id,6字节
  • B5 00 00 00 05 01 10:回滚段指针,7字节
  • 61:c1列,61表示字符a

record2:

<code>c097->15101 00 00 18 00 18 |80 00 00 02 |00 00 00 0C 81 E8 |B6 00 00 00 05 01 10 |/<code>
  • record header:01 00 00 18 00 18
  • 00 00 18 -> 00000000 00000000 00011000,0000info flag,0000 record owned, 00000000 00011表示heap no=3
  • 00 18表示下条记录的相对偏移量
  • 分析同上

record3:

<code>c08f->17501 00 00 00 20 FF C1 |80 00 00 03 |00 00 00 0C 81 E9 |B7 00 00 00 05 01 10 |61/<code>
  • record header:01 00 00 00 20 FF C1
  • 00 00 20 -> 00000000 00000000 00100000,0000info flag,0000 record owned, 00000000 00100表示heap no=4
  • 分析同上

Page Directory:

00 70 00 63 page directory是倒序存储的,因此00 63是最初行的相对位置,即c063,也就是infimum记录的起始位置,00 70对应位置0c70,对应supremum的起始位置

page tailer

  • 38 AD C1 F5 : checksum值
  • 4E 07 B2 CA:对应LSN的低4字节

额外实验

<code>root@mysqldb 15:34:  [xucl]> show create table t\G*************************** 1. row ***************************       Table: tCreate Table: CREATE TABLE `t` (  `id` int(11) NOT NULL AUTO_INCREMENT,  `c1` varchar(10) DEFAULT NULL,  `c2` varchar(10) DEFAULT NULL,  PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb41 row in set (0.00 sec)root@mysqldb 15:34:  [xucl]> select * from t;+----+------+------+| id | c1   | c2   |+----+------+------+|  1 | a    | NULL ||  2 | a    | a    ||  3 | NULL | NULL |+----+------+------+3 rows in set (0.00 sec)/<code>

提取用户记录部分

<code>01 02    |00 00 10 00 1A    |80 00 00 01 00 00 00 0C 81 ED BA 00 00 00 05 01 10 |61 01 01 00 |00 00 18 00 19    |80 00 00 02 00 00 00 0C 81 F5 C0 00 00 00 05 01 10 |61 6103       |00 00 20 FF BE    |80 00 00 03 00 00 00 0C 81 FD A6 00 00 00 05 01 10 |/<code>

为了观察Null和变长字段,我额外做了一个实验

  • 01 02 -> 00000001 00000010,第一个字节表示变长字段c1长度为1,第二个字节表示第二个列c2为null
  • 01 01 00 -> 00000001 00000001 00000000,第一个字节表示变长字段c1长度为1,第二个字节表示变长字段c2长度为1,第三个字节表示没有字段为null
  • 03 -> 00000011,改字节表示第二个列、第三个列均为null

上次遗留问题,关于heap_top如何计算出来?

heaptop的其实就是最后一条记录往后第一个free的位置,加入最后一条记录的偏移量为189,假设最后一行的长度为32字节(5字节record header + 27字节),那么heaptop就是189+27=216了。


总结

  1. 简直手把手教了如何通过ue或者hexdump来观察innodb page结构
  2. 肉眼查看确实比较费力,建议还是使用专业工具
  3. 通过这种方法,能够对innodb page有更加深入的理解,例如上次遗留的问题就通过这次实验解惑了
教你如何使用UE观察InnoDB Page结构-爱可生


分享到:


相關文章: