百度云盤地址:
10多年專注成都網(wǎng)站制作,成都企業(yè)網(wǎng)站建設(shè),個(gè)人網(wǎng)站制作服務(wù),為大家分享網(wǎng)站制作知識(shí)、方案,網(wǎng)站設(shè)計(jì)流程、步驟,成功服務(wù)上千家企業(yè)。為您提供網(wǎng)站建設(shè),網(wǎng)站制作,網(wǎng)頁設(shè)計(jì)及定制高端網(wǎng)站建設(shè)服務(wù),專注于成都企業(yè)網(wǎng)站建設(shè),高端網(wǎng)頁制作,對(duì)成都軟裝設(shè)計(jì)等多個(gè)領(lǐng)域,擁有豐富的網(wǎng)站維護(hù)經(jīng)驗(yàn)。
http://pan.baidu.com/s/1qYnyVWo
InnoDB中索引塊的內(nèi)部組織一直是大家比較感興趣并且樂于研究的東西,我們從很多書籍和文章都不惜筆墨進(jìn)行大量的描述比如<>中就能感受到作者用了大量篇幅描述什么是slot、什么是heap、記錄的邏輯和物理順序是怎么樣的。
但是我們卻很難直觀的看到,因?yàn)閿?shù)據(jù)文件是二進(jìn)制文件。雖然我們可以通過例如LINUX的hexdump等類似命令進(jìn)行查看,但是大量的16進(jìn)制信息很難直觀的提取出各種有用的信息,相信不少人和筆者一樣都是通過肉眼進(jìn)行查看,但是這顯然是一種吃力又不討好的方法。
在Oracle中我們可以通過dump block的方法查看block的信息,那么InnoDB是否也可以這樣呢?
本著這種讓大家更加直觀的觀察到底層索引塊的信息的宗旨,筆者直接借用源碼中的各種宏定義,使用C++和STL list容器實(shí)現(xiàn)了這樣一個(gè)工具innblock。由于工作原因不能全身心投入代碼編寫,代碼有些混亂。所以如果有bug還請(qǐng)大家見諒以及提出,筆者會(huì)盡快進(jìn)行更新,感謝。
index page(索引頁、索引塊),InnoDB表是基于聚集索引的索引組織表,整個(gè)表其實(shí)不是聚集索引,就是普通索引。因此InnoDB表空間文件中,數(shù)據(jù)頁其實(shí)也是索引頁,所以下面我們統(tǒng)稱為索引頁,英文用page no表示;
本工具有2個(gè)功能。
第一個(gè)scan功能用于查找ibd文件中所有的索引頁。
第二個(gè)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 ------------------------------------------------------------------------
[root@test test]# ./innblock testblock.ibd scan 16
[root@test test]# ./innblock testblock.ibd 3 16
可以執(zhí)行 innblock help 獲得更詳細(xì)的使用幫助信息。
首先,創(chuàng)建測(cè)試表,填充數(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;
[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個(gè)索引,索引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 | +-------------+----------+----------------+-------------+------------+------------+----------+------------+---------+------------+
我們選取 pageno=3 那個(gè)索引頁進(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ì)的解釋,這里單獨(dú)對(duì)analyze功能解析數(shù)據(jù)塊的輸出詳解一番,并且我也會(huì)給出這些值來自源碼的哪個(gè)宏定義。這部分知識(shí)點(diǎn)在<>中也有詳細(xì)說明。
[block_no]:page offset no inside space,begin is 0(取自 FIL_PAGE_OFFSET)
索引頁碼(index page no),該頁相對(duì)于表空間的偏移量,從0開始計(jì)數(shù)。如果page no = 3,則實(shí)際上是第4個(gè)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的記錄(這種記錄會(huì)被放到索引頁的garbage隊(duì)列中),以及兩個(gè)偽記錄INFIMUM/SUPREMUM。
[n_rows]:number of records not include delete rows after pruge and INFIMUM/SUPREMUM(PAGE_N_RECS)
本索引頁中的記錄數(shù),不含deleted且已被purged的記錄,以及兩個(gè)偽記錄INFIMUM、SUPREMUM。
[heap_top]:pointer offset to record heap top (PAGE_HEAP_TOP)
指向本索引頁已分配的最大物理存儲(chǔ)空間的偏移量。
[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,則這個(gè)偏移量為空。通過判斷索引頁內(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)
向同一個(gè)方向插入數(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個(gè)值只在root節(jié)點(diǎn)會(huì)有信息,分別表示了葉子段和非葉子段的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)
對(duì)于本工具而言始終為B+ TREE,因?yàn)椴恢С制渌黳age type。
[level]:level of the node in an index tree; the leaf level is the level 0(PAGE_LEVEL)
本索引頁所處的B+ TREE的層級(jí)。注意,葉子結(jié)點(diǎn)的PAGE LEVEL為0。
Total used rows:5 used rows list(logic):
not delete purge rows and not delete logic sequence list(next offset list).
這個(gè)鏈表是邏輯有序鏈表,也是我們平時(shí)所說的塊內(nèi)數(shù)據(jù)有序的展示。它的順序當(dāng)然按照主鍵或者ROWID進(jìn)行排列,因?yàn)槭峭ㄟ^物理偏移量鏈表實(shí)現(xiàn)的,實(shí)際上就是邏輯上有序。我在實(shí)現(xiàn)的時(shí)候?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).
這個(gè)鏈表是物理上的順序,實(shí)際上就是heap no的順序,我在實(shí)現(xiàn)的時(shí)候?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).
這個(gè)鏈表是邏輯上的,也就是被deleted且被purged后的記錄都存在于這個(gè)鏈表中,通過讀取塊的PAGE_FREE獲取鏈表信息。
Total slot:2 slot list:
slot physics sequence list.
這是slot(槽的)信息,通過掃描塊尾部8字節(jié)以前信息進(jìn)行分析得到,我們可以發(fā)現(xiàn)在slot中存儲(chǔ)的是記錄的偏移量。
在這里鏈表中包含一些信息,這里就用help中的解析給出了。
本節(jié)全部使用測(cè)試表如下:
mysql> create table testblock ( id1 int primary key, name varchar(30), id3 int, key(name), key(id3) );
初始化測(cè)試數(shù)據(jù):
mysql> insert into testblock values(1,'gao',1),(2,'gao',2),(3,'gao',3),(4,'gao',4);
發(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 = Y,offset = 127,這條記錄只是delete,但還沒 commit,也還沒被 purged,因此不會(huì)出現(xiàn)在 del rows list鏈表中。
同時(shí)注意到幾個(gè)信息:
三個(gè)信息結(jié)合起來看,表示還沒有真正被清除的數(shù)據(jù)。
接著上面的事務(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,同時(shí)我們觀察到
可見,commit且被purged的數(shù)據(jù)才是真正的刪除(清除)。
上面刪除的記錄的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中的空間,因?yàn)閯h除記錄的空間根本放不下這條新記錄,所以只能重新分配。同時(shí)我們注意到 **heap_top = 279 ** ,這里也發(fā)生了變化,體現(xiàn)了實(shí)際為這行數(shù)據(jù)分配了新的heapno。
在上面的基礎(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了,同時(shí) heap_top = 279 ** 也沒有變化,del_bytes:31** 變成了 del_bytes:0,都充分說明了這塊空間得到重用。
清空數(shù)據(jù)表后執(zhí)行測(cè)試
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] 的記錄會(huì)放在del list鏈表的最頭部,也就是[del list header] => [id1=3] => [id1=4]。雖然 [id=4] 的記錄空間足以容下新記錄 (5,'gaopeng’,5),但并沒被重用。因?yàn)镮nnoDB只檢測(cè)第一個(gè) del list 中的第一個(gè)空位 [id1=3],顯然這個(gè)記錄空間不足以容下新記錄 (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 的記錄。
從重組函數(shù) btr_page_reorganize_low 來看,PAGE_GARBAGE確實(shí)包含了碎片空間。
清空數(shù)據(jù)表后執(zhí)行測(cè)試
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,這個(gè)剛好就是 'gaopeng' 7字節(jié)減去 'gao' 3字節(jié)剩下的4字節(jié),我們也看到了 [heapno=5] 這個(gè)記錄被重用了(del list為空,heaono=5的記錄 delflag 不為 Y)。
總之本工具可以按照你的想法進(jìn)行各種測(cè)試和觀察。
實(shí)際上本工具我并沒有顯示的分配內(nèi)存,內(nèi)存分配基本使用了STL LIST容器檢測(cè)結(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
本工具基本采集了InnoDB索引頁全部固定信息,希望能夠幫助大家更方便獲得各種信息,效率顯然高于肉眼看二進(jìn)制文件,這是作者在分析InnoDB遇到的困境,也是寫這個(gè)小工具的出發(fā)點(diǎn)。
最后再次感謝葉金榮對(duì)工具審核&建議,同時(shí)感謝 MySQL運(yùn)維內(nèi)參 三位作者周彥偉、王竹峰、強(qiáng)昌金對(duì)本工具的認(rèn)可,這也是我個(gè)人最大的榮耀。
作者微信