innblock 工具| InnoDB page觀察利器
innblock | InnoDB page觀察利器
特別鳴謝
- 筆者是知數堂早期學員,最初有寫這麼一個工具的想法也得到葉金榮老師的認可和鼓勵,這個想法也整整耗掉了好幾個晚上的休息時間,這裡再次感謝葉金榮老師對工具稽核,葉老師的經驗和學識是每一位學員寶貴的財富。
- 感謝<>主要作者周彥偉、王竹峰、強昌金對本工具的認可並授權引用部分內容,如果大家對本文的內容感到吃力可以自行參考該書,也可以和書中部分章節配合使用學習。
- 感謝我所在的易極付公司DBA團隊同事戴正勇、楊海波、田興椿、鄒啟健,在我研究和編寫程式碼的時候承擔了大部分的資料庫相關的工作,能在重慶遇到你們是我的榮幸,你們是最出色的。
工具獲取
百度雲盤地址:
一、前言
InnoDB中索引塊的內部組織一直是大家比較感興趣並且樂於研究的東西,我們從很多書籍和文章都不惜筆墨進行大量的描述比如<>中就能感受到作者用了大量篇幅描述什麼是slot、什麼是heap、記錄的邏輯和物理順序是怎麼樣的。
但是我們卻很難直觀的看到,因為資料檔案是二進位制檔案。雖然我們可以透過例如LINUX的hexdump等類似命令進行檢視,但是大量的16進位制資訊很難直觀的提取出各種有用的資訊,相信不少人和筆者一樣都是透過肉眼進行檢視,但是這顯然是一種吃力又不討好的方法。
在Oracle中我們可以透過dump block的方法檢視block的資訊,那麼InnoDB是否也可以這樣呢?
本著這種讓大家更加直觀的觀察到底層索引塊的資訊的宗旨,筆者直接借用原始碼中的各種宏定義,使用C++和STL list容器實現了這樣一個工具innblock。由於工作原因不能全身心投入程式碼編寫,程式碼有些混亂。所以如果有bug還請大家見諒以及提出,筆者會盡快進行更新,感謝。
約定
index page(索引頁、索引塊),InnoDB表是基於聚集索引的索引組織表,整個表其實不是聚集索引,就是普通索引。因此InnoDB表空間檔案中,資料頁其實也是索引頁,所以下面我們統稱為索引頁,英文用page no表示;
二、innblock簡介
本工具有2個功能。
第一個scan功能用於查詢ibd檔案中所有的索引頁。
第二個analyze功能用於掃描資料塊裡的row data。
先看下 help 輸出
------------------------------------------------------------------------ [Author]:gaopeng [Blog]:blog.itpub.net/7728585/abstract/1/ [QQ]:22389860 [Review]:yejinrong@zhishutang [Blog]:imysql.com [QQ]:4700963 -------USAGE:../innblock Datafile [scan/pageno] Blocksize [Datafile]:innodb data file! [scan]:physical scan data file to find index level and index block no [pageno]:which block you will parse [Blocksize](KB):block size of KB general is 16k only 4k/8k/16k/32k ------------------------------------------------------------------------
- scan功能
[root@test test]# ./innblock testblock.ibd scan 16
- analyze功能
[root@test test]# ./innblock testblock.ibd 3 16
可以執行 innblock help 獲得更詳細的使用幫助資訊。
三、innblock的限制
- 不支援REDUNDANT行格式的資料檔案;
- 只支援LINUX x64平臺;
- 本工具直接讀取物理檔案,部分dirty page可能延時刷盤而未能被讀取到,可以讓InnoDB及時刷盤再重新讀取;
- 最好在MySQL 5.6/5.7版本下測試;
- 只能解析索引頁,不支援inode page、undo log等型別的page;
- scan功能會包含delete後的索引塊和drop了的索引塊.
- 不能讀取詳細的row data;
- 建議採用獨立表空間模式,更便於觀察;
- 建議僅在測試環境下學習和研究使用。
四、innblock怎麼用
首先,建立測試表,填充資料
mysql> create table testblock ( id1 int primary key, name varchar(30), id3 int, key(name), key(id3)); mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gao',4); mysql> delete from testblock where id1=1;
1. 測試scan功能,掃描所有index page
[root@test]# innblock testblock.ibd scan 16 ------------------------------------------------------------------------ Welcome to use this block analyze tool: [Author]:gaopeng [Blog]:blog.itpub.net/7728585/abstract/1/ [QQ]:22389860 [Review]:yejinrong@zhishutang [Blog]:imysql.com [QQ]:4700963 ------------------------------------------------------------------------ Datafile Total Size:131072 ===INDEX_ID:248 level0 total block is (1) block_no: 3,level: 0|*| ===INDEX_ID:249 level0 total block is (1) block_no: 4,level: 0|*| ===INDEX_ID:250 level0 total block is (1) block_no: 5,level: 0|*|
我們發現有3個索引,索引ID(INDEX_ID)分別是 248、249、250,檢視資料字典確認
mysql> SELECT A.SPACE AS TBL_SPACEID, A.TABLE_ID, A.NAME AS TABLE_NAME, FILE_FORMAT, ROW_FORMAT, SPACE_TYPE, B.INDEX_ID , B.NAME AS INDEX_NAME, PAGE_NO, B.TYPE AS INDEX_TYPE FROM INNODB_SYS_TABLES A LEFT JOIN INNODB_SYS_INDEXES B ON A.TABLE_ID =B.TABLE_ID WHERE A.NAME = 'test/testblock’; +-------------+----------+----------------+-------------+------------+------------+----------+------------+---------+------------+ | TBL_SPACEID | TABLE_ID | TABLE_NAME | FILE_FORMAT | ROW_FORMAT | SPACE_TYPE | INDEX_ID | INDEX_NAME | PAGE_NO | INDEX_TYPE | +-------------+----------+----------------+-------------+------------+------------+----------+------------+---------+------------+ | 242 | 168 | test/testblock | Barracuda | Dynamic | Single | 248 | PRIMARY | 3 | 3 | | 242 | 168 | test/testblock | Barracuda | Dynamic | Single | 249 | name | 4 | 0 | | 242 | 168 | test/testblock | Barracuda | Dynamic | Single | 250 | id3 | 5 | 0 | +-------------+----------+----------------+-------------+------------+------------+----------+------------+---------+------------+
2. analyze功能展示
我們選取 pageno=3 那個索引頁進行掃描,可見下面資訊
[root@test test]# innblock testblock.ibd 3 16 ------------------------------------------------------------------------ Welcome to use this block analyze tool: [Author]:gaopeng [Blog]:blog.itpub.net/7728585/abstract/1/ [QQ]:22389860 [Review]:yejinrong@zhishutang [Blog]:imysql.com [QQ]:4700963 ------------------------------------------------------------------------ ==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:6 n_rows:3 heap_top:244 del_bytes:31 last_ins_offset:0 page_dir:2 page_n_dir:3 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510679871 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:5 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (5) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 -----Total used rows:5 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:1 del rows list(logic): (1) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0 -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:4 (2) INFIMUM slot offset:99 n_owned:1
五、輸出資訊詳解
我在工具的help文件中也有詳細的解釋,這裡單獨對analyze功能解析資料塊的輸出詳解一番,並且我也會給出這些值來自原始碼的哪個宏定義。這部分知識點在<>中也有詳細說明。
1、基本資訊(Block base info)
-
[block_no]:page offset no inside space,begin is 0(取自 FIL_PAGE_OFFSET)
索引頁碼(index page no),該頁相對於表空間的偏移量,從0開始計數。如果page no = 3,則實際上是第4個index page。 -
[space_id]:this contains the space id of the page(FIL_PAGE_SPACE_ID)
本索引頁所屬的表空間ID,可以在 INNODB_SYS_TABLES、INNODB_SYS_TABLESPACES、INNODB_SYS_DATAFILES 等系統檢視中檢視。 -
[index_id]:index id where the page belongs.This field should not be written to after page creation. (PAGE_INDEX_ID)
本索引頁所屬的索引ID,可以在 INNODB_SYS_INDEXES 系統檢視中檢視。 -
[slot_nums]:number of slots in page directory(PAGE_N_DIR_SLOTS)
本索引頁中所包含的slot(槽)的數量。 -
[heaps_rows]:number of records in the heap include delete rows after purge and INFIMUM/SUPREMUM(取自PAGE_N_HEAP)
本索引頁中的全部記錄數量,這其中包含了已經deleted且已被purged的記錄(這種記錄會被放到索引頁的garbage佇列中),以及兩個偽記錄INFIMUM/SUPREMUM。 -
[n_rows]:number of records not include delete rows after pruge and INFIMUM/SUPREMUM(PAGE_N_RECS)
本索引頁中的記錄數,不含deleted且已被purged的記錄,以及兩個偽記錄INFIMUM、SUPREMUM。 -
[heap_top]:pointer offset to record heap top (PAGE_HEAP_TOP)
指向本索引頁已分配的最大物理儲存空間的偏移量。 -
[del_bytes]:number of bytes in deleted records after purge(PAGE_GARBAGE)
本索引頁中所有deleted了的且已被purged的記錄的總大小。 -
[last_ins_offset]:pointer to the last inserted record, or NULL if this info has been reset by a delete(PAGE_LAST_INSERT)
指向本索引頁最後插入記錄的位置偏移量,如果最後操作是delete,則這個偏移量為空。透過判斷索引頁內資料最後插入的方向,用於索引分裂判斷。 -
[page_dir]:last insert direction: PAGE_LEFT, ...(PAGE_DIRECTION)
本索引頁中資料最後插入的方向,同樣用於索引分裂判斷。 -
[page_n_dir]:number of consecutive inserts to the same direction(PAGE_N_DIRECTION)
向同一個方向插入資料的行數,同樣用於索引分裂中進行判斷 -
[leaf_inode_space leaf_inode_pag_no leaf_inode_offset]:leaf segment postion and in inode block offset,only root block(PAGE_BTR_SEG_LEAF開始 10位元組)
-
[no_leaf_inode_space no_leaf_inode_pag_no no_leaf_inode_offset]:no_leaf segment postion and in inode block offset,only root block(取自PAGE_BTR_SEG_TOP 開始 10位元組)
這6個值只在root節點會有資訊,分別表示了葉子段和非葉子段的inode的位置和在inode塊中的偏移量,其他塊都為0。 -
[last_modify_lsn]:lsn of the end of the newest modification log record to the page(FIL_PAGE_LSN)
本塊最後一次修改的LSN。 -
[page_type]:for this tool only B+_TREE(FIL_PAGE_TYPE)
對於本工具而言始終為B+ TREE,因為不支援其它page type。 -
[level]:level of the node in an index tree; the leaf level is the level 0(PAGE_LEVEL)
本索引頁所處的B+ TREE的層級。注意,葉子結點的PAGE LEVEL為0。
2、四個相關連結串列(Block list info)
-
Total used rows:5 used rows list(logic):
not delete purge rows and not delete logic sequence list(next offset list).
這個連結串列是邏輯有序連結串列,也是我們平時所說的塊內資料有序的展示。它的順序當然按照主鍵或者ROWID進行排列,因為是透過物理偏移量連結串列實現的,實際上就是邏輯上有序。我在實現的時候實際上是取了INFIMUM的偏移量開始進行掃描直到最後,但是注意被deleted且已經被purged的記錄不在其中。 -
Total used rows:5 used rows list(phy):
not delete purge rows and not delete physics sequence list(sort by heap no).
這個連結串列是物理上的順序,實際上就是heap no的順序,我在實現的時候實際上就是將上面的邏輯連結串列按照heap no進行排序完成的,所以塊內部是邏輯有序物理無序的,同樣注意被deleted且已被purged的記錄不在其中。 -
Total del rows:1 del rows list(logic):
purge delete logic sequence list(next offset list).
這個連結串列是邏輯上的,也就是被deleted且被purged後的記錄都存在於這個連結串列中,透過讀取塊的PAGE_FREE獲取連結串列資訊。 -
Total slot:2 slot list:
slot physics sequence list.
這是slot(槽的)資訊,透過掃描塊尾部8位元組以前資訊進行分析得到,我們可以發現在slot中儲存的是記錄的偏移量。
在這裡連結串列中包含一些資訊,這裡就用help中的解析給出了。
- [record offset]:real offset in block of this record.
- [heapno]:physics heapno of this record.
- [n_owned]:if this record is slot record n_owned is how many this slot include,other is 0.
- [delflag]:this record is delete will Y,if not purge in list 1,if purge in list 3.
-
[rectype]:
[REC_STATUS_ORDINARY=0(B+ leaf record)
[REC_STATUS_NODE_PTR=1(not B+ leaf record)]
[REC_STATUS_INFIMUM=2]
[REC_STATUS_SUPREMUM=3] - [slot offset]:where(offset) this slot point,this is a record offset.no purge delete record.
- [n_owned]:how many this slot include recorods.no purge delete record.
六、幾個測試案列
本節全部使用測試表如下:
mysql> create table testblock ( id1 int primary key, name varchar(30), id3 int, key(name), key(id3) );
初始化測試資料:
mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gao',4);
1、執行delete後還未commit的記錄只打 delete 標記
發起事務,先執行delete,暫不commit
mysql> begin; delete from testblock where id1=1;
分析結果:
[root@test]# innblock testblock.ibd 3 16 ==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:6 n_rows:4 heap_top:244 del_bytes:0 last_ins_offset:220 page_dir:2 page_n_dir:3 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510695376 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:6 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (6) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 -----Total used rows:6 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 (3) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0 (4) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (6) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:0 del rows list(logic): -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:5 (2) INFIMUM slot offset:99 n_owned:1
我們看到其中有一條記錄是
(2) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0
其 delflag = Y,offset = 127,這條記錄只是delete,但還沒 commit,也還沒被 purged,因此不會出現在 del rows list連結串列中。
同時注意到幾個資訊:
- del_bytes:0
- n_rows:4
- heaps_rows:6
三個資訊結合起來看,表示還沒有真正被清除的資料。
2、執行delete後commit的記錄,被purged後真正被清除,進入刪除連結串列
接著上面的事務,繼續執行commit
mysql> commit; Query OK, 0 rows affected (0.00 sec)
分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:6 n_rows:3 heap_top:244 del_bytes:31 last_ins_offset:0 page_dir:2 page_n_dir:3 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510695802 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:5 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (5) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 -----Total used rows:5 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:1 del rows list(logic): (1) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0 -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:4 (2) INFIMUM slot offset:99 n_owned:1
我們看到,執行commit,這條偏移量為127的記錄被purged後入了del rows list連結串列
(1) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0
其delflag = Y,同時我們觀察到
- del_bytes:31 //上一次看到的值是 0
- n_rows:3 //上一次看到的值是 4
- heaps_rows:6 //和上一次的值一樣,因為這裡計算的是物理記錄數
可見,commit且被purged的資料才是真正的刪除(清除)。
3、先刪除後insert更大新記錄,舊的heap no不會重用
上面刪除的記錄的heapno為2,接著插入新記錄
insert into testblock values(5,'gaopeng',1);
顯然它的長度大於刪除記錄的長度。
分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:7 n_rows:4 heap_top:279 del_bytes:31 last_ins_offset:251 page_dir:5 page_n_dir:0 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510695994 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:6 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:251 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 (6) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 -----Total used rows:6 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (6) normal record offset:251 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:1 del rows list(logic): (1) normal record offset:127 heapno:2 n_owned 0,delflag:Y minflag:0 rectype:0 -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:5 (2) INFIMUM slot offset:99 n_owned:1
我們看到有一條新記錄
(5) normal record offset:251 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0
這條記錄的heapno = 6,而刪除的舊記錄 heapno=2,這表明它沒有重用del rows list中的空間,因為刪除記錄的空間根本放不下這條新記錄,所以只能重新分配。同時我們注意到 **heap_top = 279 ** ,這裡也發生了變化,體現了實際為這行資料分配了新的heapno。
4、delete後,再insert更小或者相同大小記錄,heap no會重用
在上面的基礎上,我們插入新記錄
insert into testblock values(6,'gao',1);
分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:7 n_rows:5 heap_top:279 del_bytes:0 last_ins_offset:127 page_dir:2 page_n_dir:1 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510700272 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:7 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:251 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 (6) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (7) SUPREMUM record offset:112 heapno:1 n_owned 6,delflag:N minflag:0 rectype:3 -----Total used rows:7 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 6,delflag:N minflag:0 rectype:3 (3) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (6) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (7) normal record offset:251 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:0 del rows list(logic): -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:6 (2) INFIMUM slot offset:99 n_owned:1
我們這次新寫入的資料長度和刪除的資料長度一致,我們發現heapno重用了del rows list中的記錄沒有了,而在資料邏輯順序中多了一條
(6) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0
我們發現heapno=2的記錄 delflag 不再是 Y了,同時 heap_top = 279 ** 也沒有變化,del_bytes:31** 變成了 del_bytes:0,都充分說明了這塊空間得到重用。
5、測試del list中的空間重用只會檢測第一個條刪除的記錄
清空資料表後執行測試
mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gaopeng',4); mysql> delete from testblock where id1=4; mysql> delete from testblock where id1=3; mysql> insert into testblock values(5,'gaopeng',5);
在這裡,我們先刪除 [id1=4] 記錄,後刪除 [id1=3] 記錄。
由於del list是頭插法,所以後刪除的 [id1=3] 的記錄會放在del list連結串列的最頭部,也就是[del list header] => [id1=3] => [id1=4]。雖然 [id=4] 的記錄空間足以容下新記錄 (5,'gaopeng’,5),但並沒被重用。因為InnoDB只檢測第一個 del list 中的第一個空位 [id1=3],顯然這個記錄空間不足以容下新記錄 (5,’gaopeng',5),所以還是新開闢了heap。
分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:7 n_rows:3 heap_top:283 del_bytes:66 last_ins_offset:255 page_dir:5 page_n_dir:0 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510728551 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:5 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:255 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 (5) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 -----Total used rows:5 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 (3) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:255 heapno:6 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:2 del rows list(logic): (1) normal record offset:189 heapno:4 n_owned 0,delflag:Y minflag:0 rectype:0 (2) normal record offset:220 heapno:5 n_owned 0,delflag:Y minflag:0 rectype:0 -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:4 (2) INFIMUM slot offset:99 n_owned:1
我們看到 del list 中共有2條記錄(沒被重用),卻新增加了 heapno = 6 的記錄。
6、del_bytes(PAGE_GARBAGE)是否包含碎片空間
從重組函式 btr_page_reorganize_low 來看,PAGE_GARBAGE確實包含了碎片空間。
清空資料表後執行測試
mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gaopeng',4); mysql> delete from testblock where id1=4;
分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:6 n_rows:3 heap_top:248 del_bytes:35 last_ins_offset:0 page_dir:2 page_n_dir:3 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510748484 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:5 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 -----Total used rows:5 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 4,delflag:N minflag:0 rectype:3 (3) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:1 del rows list(logic): (1) normal record offset:220 heapno:5 n_owned 0,delflag:Y minflag:0 rectype:0 -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:4 (2) INFIMUM slot offset:99 n_owned:1
注意這裡 del_bytes:35 就是刪除這條記錄的空間的使用量。接下來執行SQL
mysql> insert into testblock values(5,'gao',5);
再次分析結果:
==== Block base info ==== block_no:3 space_id:242 index_id:248 slot_nums:2 heaps_rows:6 n_rows:4 heap_top:248 del_bytes:4 last_ins_offset:220 page_dir:5 page_n_dir:0 leaf_inode_space:242 leaf_inode_pag_no:2 leaf_inode_offset:242 no_leaf_inode_space:242 no_leaf_inode_pag_no:2 no_leaf_inode_offset:50 last_modify_lsn:510748643 page_type:B+_TREE level:0 ==== Block list info ==== -----Total used rows:6 used rows list(logic): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (3) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 (6) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 -----Total used rows:6 used rows list(phy): (1) INFIMUM record offset:99 heapno:0 n_owned 1,delflag:N minflag:0 rectype:2 (2) SUPREMUM record offset:112 heapno:1 n_owned 5,delflag:N minflag:0 rectype:3 (3) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0 (4) normal record offset:158 heapno:3 n_owned 0,delflag:N minflag:0 rectype:0 (5) normal record offset:189 heapno:4 n_owned 0,delflag:N minflag:0 rectype:0 (6) normal record offset:220 heapno:5 n_owned 0,delflag:N minflag:0 rectype:0 -----Total del rows:0 del rows list(logic): -----Total slot:2 slot list: (1) SUPREMUM slot offset:112 n_owned:5 (2) INFIMUM slot offset:99 n_owned:1
注意到 del_bytes:4,這個剛好就是 'gaopeng' 7位元組減去 'gao' 3位元組剩下的4位元組,我們也看到了 [heapno=5] 這個記錄被重用了(del list為空,heaono=5的記錄 delflag 不為 Y)。
總之本工具可以按照你的想法進行各種測試和觀察。
七、記憶體洩露檢測
實際上本工具我並沒有顯示的分配記憶體,記憶體分配基本使用了STL LIST容器檢測結果如下:
==11984== LEAK SUMMARY: ==11984== definitely lost: 0 bytes in 0 blocks ==11984== indirectly lost: 0 bytes in 0 blocks ==11984== possibly lost: 0 bytes in 0 blocks ==11984== still reachable: 568 bytes in 1 blocks ==11984== suppressed: 0 bytes in 0 blocks ==11984== Reachable blocks (those to which a pointer was found) are not shown. ==11984== To see them, rerun with: --leak-check=full --show-reachable=yes
八、總結
本工具基本採集了InnoDB索引頁全部固定資訊,希望能夠幫助大家更方便獲得各種資訊,效率顯然高於肉眼看二進位制檔案,這是作者在分析InnoDB遇到的困境,也是寫這個小工具的出發點。
最後再次感謝葉金榮對工具稽核&建議,同時感謝 MySQL運維內參 三位作者周彥偉、王竹峰、強昌金對本工具的認可,這也是我個人最大的榮耀。
作者微信
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7728585/viewspace-2145616/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- InnoDB: Error: space id and page n:o stored in the page?Error
- InnoDB從內分析之Page(二)
- MySQL5.7 InnoDB Page CompressionMySql
- InnoDB:Failingassertion:page_get_n_recs(page)>1AI
- MySQL:Innodb page clean 執行緒 (二) 解析MySql執行緒
- 解決mysql innodb page corrupt一例MySql
- 遭遇 bug InnoDB: Failing assertion: page_get_n_recs(page) > 1AI
- MySQL:Innodb page clean 執行緒 (一) 基礎MySql執行緒
- innodb page重組空間壓縮函式(btr_page_reorganize_low)註釋函式
- MySQL原理 - InnoDB引擎 - 行記錄儲存 - Off-page 列MySql
- 關於MYSQL INNODB index page header學習和實驗總結MySqlIndexHeader
- 介紹觀察Jboss的工具
- MySQL 8.0 Reference Manual(讀書筆記78節-- InnoDB Table and Page Compression (1))MySql筆記
- MySQL 8.0 Reference Manual(讀書筆記79節-- InnoDB Table and Page Compression (2))MySql筆記
- 【MySQL】Innodb 恢復工具介紹MySql
- 老司機的神兵利器-效率工具
- 【工具】MySQL 安裝利器---SandboxMySql
- 頁面前端效能除錯工具yslow,Page Speed前端除錯
- 【MySQL】二、Innodb 恢復工具介紹MySql
- innodb儲存引擎備份工具--Xtrabackup儲存引擎
- 深入探索Chrome開發者工具:開發者的利器Chrome
- Kiali——Istio Service Mesh 的可觀察性工具
- Java爬蟲利器HTML解析工具-JsoupJava爬蟲HTMLJS
- Auto Refresh Page for Mac(自動重新整理網頁工具)Mac網頁
- INNODB 熱備工具試驗與總結 薦
- 雲安全:防護“工具”還是攻擊“利器”
- 今日推薦工具:全球衛生觀察站資料
- 自動化逆向輔助利器 -- Capa工具介紹
- [工具]PHP 中的日期時間處理利器 – CarbonPHP
- [工具]PHP 中的日期時間處理利器 - CarbonPHP
- SRE 必備利器:域名 DNS 探測排障工具DNS
- MySQL data pageMySql
- create-a-page
- Mendix Page Template
- 【Linux 工具】伺服器檔案傳輸利器 lrzszLinux伺服器
- [JVM工具(1)] 堆疊檢查利器jstat的使用JVMJS
- 提升效率的利器——Rocket Typist Pro 文字快速輸入工具
- 【工具】tsar 監控Linux系統狀態的利器Linux