innblock | InnoDB page觀察利器

innblock | InnoDB page觀察利器

特別鳴謝

  • 筆者是知數(shù)堂早期學(xué)員,最初有寫這么一個工具的想法也得到葉金榮老師的認(rèn)可和鼓勵褥赊,這個想法也整整耗掉了好幾個晚上的休息時間,這里再次感謝葉金榮老師對工具審核,葉老師的經(jīng)驗和學(xué)識是每一位學(xué)員寶貴的財富义矛。
  • 感謝<<MySQL運維內(nèi)參>>主要作者周彥偉、王竹峰盟萨、強昌金對本工具的認(rèn)可并授權(quán)引用部分內(nèi)容凉翻,如果大家對本文的內(nèi)容感到吃力可以自行參考該書,也可以和書中部分章節(jié)配合使用學(xué)習(xí)捻激。
  • 感謝我所在的易極付公司DBA團(tuán)隊同事戴正勇制轰、楊海波前计、田興椿、鄒啟健垃杖,在我研究和編寫代碼的時候承擔(dān)了大部分的數(shù)據(jù)庫相關(guān)的工作男杈,能在重慶遇到你們是我的榮幸,你們是最出色的调俘。

工具獲取

百度云盤地址:

http://pan.baidu.com/s/1qYnyVWo

一伶棒、前言

InnoDB中索引塊的內(nèi)部組織一直是大家比較感興趣并且樂于研究的東西,我們從很多書籍和文章都不惜筆墨進(jìn)行大量的描述比如<<MySQL運維內(nèi)參>>中就能感受到作者用了大量篇幅描述什么是slot彩库、什么是heap肤无、記錄的邏輯和物理順序是怎么樣的。

但是我們卻很難直觀的看到骇钦,因為數(shù)據(jù)文件是二進(jìn)制文件舅锄。雖然我們可以通過例如LINUX的hexdump等類似命令進(jìn)行查看,但是大量的16進(jìn)制信息很難直觀的提取出各種有用的信息司忱,相信不少人和筆者一樣都是通過肉眼進(jìn)行查看,但是這顯然是一種吃力又不討好的方法畴蹭。

在Oracle中我們可以通過dump block的方法查看block的信息坦仍,那么InnoDB是否也可以這樣呢?

本著這種讓大家更加直觀的觀察到底層索引塊的信息的宗旨叨襟,筆者直接借用源碼中的各種宏定義繁扎,使用C++和STL list容器實現(xiàn)了這樣一個工具innblock。由于工作原因不能全身心投入代碼編寫糊闽,代碼有些混亂梳玫。所以如果有bug還請大家見諒以及提出,筆者會盡快進(jìn)行更新右犹,感謝提澎。

約定

index page(索引頁、索引塊)念链,InnoDB表是基于聚集索引的索引組織表盼忌,整個表其實不是聚集索引,就是普通索引掂墓。因此InnoDB表空間文件中谦纱,數(shù)據(jù)頁其實也是索引頁,所以下面我們統(tǒng)稱為索引頁君编,英文用page no表示跨嘉;

二、innblock簡介

本工具有2個功能吃嘿。

第一個scan功能用于查找ibd文件中所有的索引頁祠乃。

第二個analyze功能用于掃描數(shù)據(jù)塊里的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

可以執(zhí)行 innblock help 獲得更詳細(xì)的使用幫助信息。

三跳纳、innblock的限制

  1. 不支持REDUNDANT行格式的數(shù)據(jù)文件忍饰;
  2. 只支持LINUX x64平臺;
  3. 本工具直接讀取物理文件寺庄,部分dirty page可能延時刷盤而未能被讀取到艾蓝,可以讓InnoDB及時刷盤再重新讀取斗塘;
  4. 最好在MySQL 5.6/5.7版本下測試赢织;
  5. 只能解析索引頁,不支持inode page馍盟、undo log等類型的page于置;
  6. scan功能會包含delete后的索引塊和drop了的索引塊.
  7. 不能讀取詳細(xì)的row data;
  8. 建議采用獨立表空間模式贞岭,更便于觀察八毯;
  9. 建議僅在測試環(huán)境下學(xué)習(xí)和研究使用。

四瞄桨、innblock怎么用

首先话速,創(chuàng)建測試表,填充數(shù)據(jù)

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|*|

我們發(fā)現(xiàn)有3個索引泊交,索引ID(INDEX_ID)分別是 248、249柱查、250廓俭,查看數(shù)據(jù)字典確認(rèn)

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 那個索引頁進(jìn)行掃描,可見下面信息

[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文檔中也有詳細(xì)的解釋研乒,這里單獨對analyze功能解析數(shù)據(jù)塊的輸出詳解一番,并且我也會給出這些值來自源碼的哪個宏定義酵紫。這部分知識點在<<MySQL運維內(nèi)參>>中也有詳細(xì)說明告嘲。

1、基本信息(Block base info)

  • [block_no]:page offset no inside space,begin is 0(取自 FIL_PAGE_OFFSET)
    索引頁碼(index page no)奖地,該頁相對于表空間的偏移量橄唬,從0開始計數(shù)。如果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 等系統(tǒng)視圖中查看侨嘀。

  • [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 系統(tǒng)視圖中查看捂襟。

  • [slot_nums]:number of slots in page directory(PAGE_N_DIR_SLOTS)
    本索引頁中所包含的slot(槽)的數(shù)量咬腕。

  • [heaps_rows]:number of records in the heap include delete rows after purge and INFIMUM/SUPREMUM(取自PAGE_N_HEAP)
    本索引頁中的全部記錄數(shù)量,這其中包含了已經(jīng)deleted且已被purged的記錄(這種記錄會被放到索引頁的garbage隊列中)葬荷,以及兩個偽記錄INFIMUM/SUPREMUM涨共。

  • [n_rows]:number of records not include delete rows after pruge and INFIMUM/SUPREMUM(PAGE_N_RECS)
    本索引頁中的記錄數(shù),不含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雕崩,則這個偏移量為空魁索。通過判斷索引頁內(nèi)數(shù)據(jù)最后插入的方向,用于索引分裂判斷盼铁。

  • [page_dir]:last insert direction: PAGE_LEFT, ...(PAGE_DIRECTION)
    本索引頁中數(shù)據(jù)最后插入的方向蛾默,同樣用于索引分裂判斷。

  • [page_n_dir]:number of consecutive inserts to the same direction(PAGE_N_DIRECTION)
    向同一個方向插入數(shù)據(jù)的行數(shù)捉貌,同樣用于索引分裂中進(jìn)行判斷

  • [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字節(jié))

  • [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字節(jié))
    這6個值只在root節(jié)點會有信息,分別表示了葉子段和非葉子段的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的層級。注意裆针,葉子結(jié)點的PAGE LEVEL為0刨摩。

2、四個相關(guān)鏈表(Block list info)

  • Total used rows:5 used rows list(logic):
    not delete purge rows and not delete logic sequence list(next offset list).
    這個鏈表是邏輯有序鏈表世吨,也是我們平時所說的塊內(nèi)數(shù)據(jù)有序的展示澡刹。它的順序當(dāng)然按照主鍵或者ROWID進(jìn)行排列,因為是通過物理偏移量鏈表實現(xiàn)的耘婚,實際上就是邏輯上有序罢浇。我在實現(xiàn)的時候?qū)嶋H上是取了INFIMUM的偏移量開始進(jìn)行掃描直到最后,但是注意被deleted且已經(jīng)被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的順序攒岛,我在實現(xiàn)的時候?qū)嶋H上就是將上面的邏輯鏈表按照heap no進(jìn)行排序完成的,所以塊內(nèi)部是邏輯有序物理無序的胞锰,同樣注意被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字節(jié)以前信息進(jìn)行分析得到誊册,我們可以發(fā)現(xiàn)在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.

六君旦、幾個測試案列

本節(jié)全部使用測試表如下:

mysql> create table testblock (
id1 int primary key,
name varchar(30),
id3 int,
key(name),
key(id3)
);

初始化測試數(shù)據(jù):

mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gao',4);

1、執(zhí)行delete后還未commit的記錄只打 delete 標(biāo)記

發(fā)起事務(wù)嘲碱,先執(zhí)行delete金砍,暫不commit

mysql> begin; delete from testblock where id1=1;

分析結(jié)果:

[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 = Yoffset = 127麦锯,這條記錄只是delete恕稠,但還沒 commit,也還沒被 purged扶欣,因此不會出現(xiàn)在 del rows list鏈表中鹅巍。

同時注意到幾個信息:

  • del_bytes:0
  • n_rows:4
  • heaps_rows:6

三個信息結(jié)合起來看,表示還沒有真正被清除的數(shù)據(jù)料祠。

2骆捧、執(zhí)行delete后commit的記錄,被purged后真正被清除髓绽,進(jìn)入刪除鏈表

接著上面的事務(wù)敛苇,繼續(xù)執(zhí)行commit

mysql> commit;
Query OK, 0 rows affected (0.00 sec)

分析結(jié)果:

==== 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

我們看到,執(zhí)行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 //和上一次的值一樣,因為這里計算的是物理記錄數(shù)

可見株茶,commit且被purged的數(shù)據(jù)才是真正的刪除(清除)来涨。

3、先刪除后insert更大新記錄启盛,舊的heap no不會重用

上面刪除的記錄的heapno為2扫夜,接著插入新記錄

insert into testblock values(5,'gaopeng',1);

顯然它的長度大于刪除記錄的長度。

分析結(jié)果:

==== 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 ** 超陆,這里也發(fā)生了變化,體現(xiàn)了實際為這行數(shù)據(jù)分配了新的heapno浦马。

4时呀、delete后,再insert更小或者相同大小記錄晶默,heap no會重用

在上面的基礎(chǔ)上谨娜,我們插入新記錄

insert into testblock values(6,'gao',1);

分析結(jié)果:

==== 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

我們這次新寫入的數(shù)據(jù)長度和刪除的數(shù)據(jù)長度一致,我們發(fā)現(xiàn)heapno重用了del rows list中的記錄沒有了磺陡,而在數(shù)據(jù)邏輯順序中多了一條

(6) normal record offset:127 heapno:2 n_owned 0,delflag:N minflag:0 rectype:0

我們發(fā)現(xiàn)heapno=2的記錄 delflag 不再是 Y了趴梢,同時 heap_top = 279 ** 也沒有變化,del_bytes:31** 變成了 del_bytes:0币他,都充分說明了這塊空間得到重用坞靶。

5、測試del list中的空間重用只會檢測第一個條刪除的記錄

清空數(shù)據(jù)表后執(zhí)行測試

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。

分析結(jié)果:

==== 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)是否包含碎片空間

從重組函數(shù) btr_page_reorganize_low 來看嘉裤,PAGE_GARBAGE確實包含了碎片空間郑临。

清空數(shù)據(jù)表后執(zhí)行測試

mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gaopeng',4);
mysql> delete from testblock where id1=4;

分析結(jié)果:

==== 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 就是刪除這條記錄的空間的使用量。接下來執(zhí)行SQL

mysql> insert into testblock values(5,'gao',5);

再次分析結(jié)果:

==== 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字節(jié)減去 'gao' 3字節(jié)剩下的4字節(jié)厢洞,我們也看到了 [heapno=5] 這個記錄被重用了(del list為空,heaono=5的記錄 delflag 不為 Y)。

總之本工具可以按照你的想法進(jìn)行各種測試和觀察躺翻。

七丧叽、內(nèi)存泄露檢測

實際上本工具我并沒有顯示的分配內(nèi)存,內(nèi)存分配基本使用了STL LIST容器檢測結(jié)果如下:

==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

八公你、總結(jié)

本工具基本采集了InnoDB索引頁全部固定信息踊淳,希望能夠幫助大家更方便獲得各種信息,效率顯然高于肉眼看二進(jìn)制文件陕靠,這是作者在分析InnoDB遇到的困境迂尝,也是寫這個小工具的出發(fā)點。
最后再次感謝葉金榮對工具審核&建議剪芥,同時感謝 MySQL運維內(nèi)參 三位作者周彥偉垄开、王竹峰、強昌金對本工具的認(rèn)可税肪,這也是我個人最大的榮耀溉躲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市寸认,隨后出現(xiàn)的幾起案子签财,更是在濱河造成了極大的恐慌续膳,老刑警劉巖饰躲,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件肴茄,死亡現(xiàn)場離奇詭異闹击,居然都是意外死亡窜骄,警方通過查閱死者的電腦和手機遵馆,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門曹仗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來仑性,“玉大人古今,你說我怎么就攤上這事屁魏。” “怎么了捉腥?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵氓拼,是天一觀的道長。 經(jīng)常有香客問我抵碟,道長桃漾,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任拟逮,我火速辦了婚禮撬统,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘敦迄。我一直安慰自己恋追,他們只是感情好凭迹,可當(dāng)我...
    茶點故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著苦囱,像睡著了一般嗅绸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上沿彭,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天朽砰,我揣著相機與錄音,去河邊找鬼喉刘。 笑死瞧柔,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的睦裳。 我是一名探鬼主播造锅,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼廉邑!你這毒婦竟也來了哥蔚?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤蛛蒙,失蹤者是張志新(化名)和其女友劉穎糙箍,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體牵祟,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡深夯,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了诺苹。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片咕晋。...
    茶點故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖收奔,靈堂內(nèi)的尸體忽然破棺而出掌呜,到底是詐尸還是另有隱情,我是刑警寧澤坪哄,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布质蕉,位于F島的核電站,受9級特大地震影響翩肌,放射性物質(zhì)發(fā)生泄漏模暗。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一摧阅、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧绷蹲,春花似錦棒卷、人聲如沸顾孽。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽若厚。三九已至,卻和暖如春蜒什,著一層夾襖步出監(jiān)牢的瞬間测秸,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工灾常, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留霎冯,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓钞瀑,卻偏偏與公主長得像沈撞,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子雕什,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,843評論 2 354

推薦閱讀更多精彩內(nèi)容