如何使用UE觀察InnoDB Page結構

導讀:

本文是對上一篇文章的延續,在閱讀本文之前建議先快速閱讀一下《InnoDB Page結構詳解》

創建表結構,插入三條數據

<code>root@mysqldb 11:01: [xucl]> show create table t\\G/<code><code>*************************** 1. row ***************************/<code><code> Table: t/<code><code>Create Table: CREATE TABLE `t` (/<code><code> `id` int(11) NOT AUTO_INCREMENT,/<code><code> `c1` varchar(10) DEFAULT ,/<code><code> PRIMARY KEY (`id`)/<code><code>) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4/<code><code>1 row in set (0.00 sec)/<code>
<code>root@mysqldb 11:01: [xucl]> select * from t;/<code><code>+----+------+/<code><code>| id | c1 |/<code><code>+----+------+/<code><code>| 1 | a |/<code><code>| 2 | |/<code><code>| 3 | a |/<code><code>+----+------+/<code><code>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 f/<code><code>c000 38 AD C1 F5 00 00 00 03 FF FF FF FF FF FF FF FF/<code><code>c010 00 00 00 11 4E 07 B2 CA 45 BF 00 00 00 00 00 00/<code><code>c020 00 00 00 00 04 D2 00 02 00 C1 80 05 00 00 00 00/<code><code>c030 00 AF 00 02 00 02 00 03 00 00 00 00 00 00 00 00/<code><code>c040 00 00 00 00 00 00 00 00 08 48 00 00 04 D2 00 00/<code><code>c050 00 02 00 F2 00 00 04 D2 00 00 00 02 00 32 01 00/<code><code>c060 02 00 1C 69 6E 66 69 6D 75 6D 00 02 00 0B 00 00/<code><code>c070 73 75 70 72 65 6D 75 6D 01 00 00 00 10 00 18 80/<code><code>c080 00 00 01 00 00 00 0C 81 E7 B5 00 00 00 05 01 10/<code><code>c090 61 01 00 00 18 00 18 80 00 00 02 00 00 00 0C 81/<code><code>c0a0 E8 B6 00 00 00 05 01 10 01 00 00 00 20 FF C1 80 /<code><code>c0b0 00 00 03 00 00 00 0C 81 E9 B7 00 00 00 05 01 10/<code><code>c0c0 61/<code><code>................................/<code><code>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->99/<code><code>infimum:01 00 02 00 1C |69 6E 66 69 6D 75 6D 00/<code>
<code>c070->112/<code><code>supremum:02 00 0B 00 00 73 75 70 72 65 6D 75 6D/<code>

record1:

<code>c07f>127/<code><code>01 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表示 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->151/<code><code>01 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->175/<code><code>01 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/<code><code>*************************** . row ***************************/<code><code> Table: t/<code><code>Create Table: CREATE TABLE `t` (/<code><code> `id` int(11) NOT AUTO_INCREMENT,/<code><code> `c1` varchar(10) DEFAULT ,/<code><code> `c2` varchar(10) DEFAULT ,/<code><code> PRIMARY KEY (`id`)/<code><code>) ENGINE=InnoDB AUTO_INCREMENT= DEFAULT CHARSET=utf8mb4/<code><code> row in set (0.00 sec)/<code>
<code>root@mysqldb 15:34: [xucl]> select * from t;/<code><code>+----+------+------+/<code><code>| id | c1 | c2 |/<code><code>+----+------+------+/<code><code>| 1 | a | |/<code><code>| 2 | a | a |/<code><code>| 3 | | |/<code><code>+----+------+------+/<code><code> 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 /<code><code>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 61/<code><code>03 |00 00 20 FF BE |80 00 00 03 00 00 00 0C 81 FD A6 00 00 00 05 01 10 |/<code>

為了觀察和變長字段,我額外做了一個實驗

  • 01 02 -> 00000001 00000010,第一個字節表示變長字段c1長度為1,第二個字節表示第二個列c2為

  • 01 01 00 -> 00000001 00000001 00000000,第一個字節表示變長字段c1長度為1,第二個字節表示變長字段c2長度為1,第三個字節表示沒有字段為

  • 03 -> 00000011,改字節表示第二個列、第三個列均為

上次遺留問題,關於heap_top如何計算出來?

heaptop的其實就是最後一條記錄往後第一個free的位置,加入最後一條記錄的偏移量為189,假設最後一行的長度為32字節(5字節record header + 27字節),那麼heaptop就是189+27=216了。

總結

  1. 簡直手把手教了如何通過ue或者hexdump來觀察innodb page結構

  2. 肉眼查看確實比較費力,建議還是使用專業工具

  3. 通過這種方法,能夠對innodb page有更加深入的理解,例如上次遺留的問題就通過這次實驗解惑了


分享到:


相關文章: