教你如何使用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結構-愛可生


分享到:


相關文章: