MySQL:InnoDB一顆B+樹(shù)可以存放多少行數(shù)據(jù)?
前言
開(kāi)門(mén)見(jiàn)山,面對(duì)這樣一個(gè)問(wèn)題,你將如何作答?
1千萬(wàn),2千萬(wàn),或者上億條數(shù)據(jù)?具體的答案不重要,當(dāng)然肯定也不會(huì)是一個(gè)固定的數(shù)目,今天我們就一起來(lái)探討探討這個(gè)問(wèn)題。
InnoDB是一種兼顧了高可靠性和高性能的通用存儲(chǔ)引擎,它擁有諸多功能和特性,體系結(jié)構(gòu)和工作原理也比較復(fù)雜。真要講明白說(shuō)透徹,不是一兩篇博文能夠?qū)崿F(xiàn)的,也不是今天的重點(diǎn)。
所以,本文不涉及太多的原理性知識(shí),咱們就針對(duì)開(kāi)頭提出的問(wèn)題,通過(guò)熟悉一些基本的概念和利用工具來(lái)驗(yàn)證,對(duì)這個(gè)問(wèn)題做到心中有數(shù)。
文件結(jié)構(gòu)
我們知道,InnoDB引擎是支持事務(wù)的,所以表里的數(shù)據(jù)肯定都是存儲(chǔ)在磁盤(pán)上的。如果在test數(shù)據(jù)庫(kù)下創(chuàng)建兩個(gè)表:t1和t2,那么在相應(yīng)的數(shù)據(jù)目錄下就會(huì)發(fā)現(xiàn)兩個(gè)文件。
[root@localhost?test]#?ls
db.opt??t1.frm??t1.ibd??t2.frm??t2.ibd
[root@localhost?test]#?pwd
/var/lib/mysql/test
其中,frm文件是表結(jié)構(gòu)信息,ibd文件是表中的數(shù)據(jù)。
表結(jié)構(gòu)信息包含MySQL表的元數(shù)據(jù)(例如表定義)的文件,比如表名、表有多少列、列的數(shù)據(jù)類(lèi)型啥的,不重要,我們先不管;
ibd文件存儲(chǔ)的是表中的數(shù)據(jù),比如數(shù)據(jù)行和索引。這個(gè)文件比較重要,它是今天我們的重點(diǎn)研究對(duì)象。
我們說(shuō),MySQL表里的數(shù)據(jù)都是存放在磁盤(pán)上的。那么在磁盤(pán)上,最小單元是扇區(qū),每個(gè)扇區(qū)可以存放512個(gè)字節(jié)的數(shù)據(jù);操作系統(tǒng)中最小單元是塊(block),最小單位是4kb。
在Windows系統(tǒng)中,我們可以通過(guò)fsutil fsinfo ntfsinfo c:來(lái)查看。
C:\Windows\system32>fsutil?fsinfo?ntfsinfo?c:
NTFS?卷序列號(hào):?????????????0x78f40b2cf40aec66
NTFS?版本:?????????????????3.1
LFS?版本:??????????????????2.0
扇區(qū)數(shù)量:??????????????????0x000000001bcb6fff
簇總數(shù):????????????????????0x0000000003796dff
可用簇:????????????????????0x0000000000a63a03
保留總數(shù):??????????????????0x00000000000017c3
每個(gè)扇區(qū)字節(jié)數(shù):????????????512
每個(gè)物理扇區(qū)字節(jié)數(shù):????????4096
每個(gè)簇字節(jié)數(shù):??????????????4096
每個(gè)?FileRecord?段字節(jié)數(shù):??1024
每個(gè)?FileRecord?段簇?cái)?shù):????0
在Linux系統(tǒng)上,可以通過(guò)以下兩個(gè)命令查看,這取決于文件系統(tǒng)的格式。
xfs_growfs?/dev/mapper/centos-root?|?grep?bsize
tune2fs?-l?/dev/mapper/centos-root?|?grep?Block
我們拉回來(lái)接著說(shuō)MySQL,InnoDB存儲(chǔ)引擎它也是有最小存儲(chǔ)單位的,叫做頁(yè)(Page),默認(rèn)大小是16kb。
我們新創(chuàng)建一個(gè)表 t3,里面任何數(shù)據(jù)都沒(méi)有,我們來(lái)看它的ibd文件。
[root@localhost?test]#?ll
總用量?18579600
-rw-r-----.?1?mysql?mysql??????????67?11月?30?20:59?db.opt
-rw-r-----.?1?mysql?mysql???????12756?12月??7?21:10?t1.frm
-rw-r-----.?1?mysql?mysql?13077839872?12月??7?21:37?t1.ibd
-rw-r-----.?1?mysql?mysql????????8608?12月??7?21:43?t2.frm
-rw-r-----.?1?mysql?mysql??5947523072?12月??7?21:52?t2.ibd
-rw-r-----.?1?mysql?mysql???????12756?12月??8?21:02?t3.frm
-rw-r-----.?1?mysql?mysql???????98304?12月??8?21:02?t3.ibd
不僅是t3,我們看到,任何表的ibd文件大小,它永遠(yuǎn)是16k的整數(shù)倍。理解這個(gè)事非常重要,MySQL從磁盤(pán)加載數(shù)據(jù)是按照頁(yè)來(lái)讀取的,即便你查詢一條數(shù)據(jù),它也會(huì)讀取一頁(yè)16k的數(shù)據(jù)出來(lái)。
聚簇索引
數(shù)據(jù)庫(kù)表中的數(shù)據(jù)都是存儲(chǔ)在頁(yè)里的,那么這一個(gè)頁(yè)可以存放多少條記錄呢?
這取決于一行記錄的大小是多少,假如一行數(shù)據(jù)大小是1k,那么理論上一頁(yè)就可以放16條數(shù)據(jù)。
當(dāng)然,查詢數(shù)據(jù)的時(shí)候,MySQL也不能把所有的頁(yè)都遍歷一遍,所以就有了索引,InnoDB存儲(chǔ)引擎用B+樹(shù)的方式來(lái)構(gòu)建索引。
聚簇索引就是按照每張表的主鍵構(gòu)造一顆B+樹(shù),葉子節(jié)點(diǎn)存放的是整行記錄數(shù)據(jù),在非葉子節(jié)點(diǎn)上存放的是鍵值以及指向數(shù)據(jù)頁(yè)的指針,同時(shí)每個(gè)數(shù)據(jù)頁(yè)之間都通過(guò)一個(gè)雙向鏈表來(lái)進(jìn)行鏈接。

如上圖所示,就是一顆聚簇索引樹(shù)的大致結(jié)構(gòu)。它先將數(shù)據(jù)記錄按照主鍵排序,放在不同的頁(yè)中,下面一行是數(shù)據(jù)頁(yè)。上面的非葉子節(jié)點(diǎn),存放主鍵值和一個(gè)指向頁(yè)的指針。
當(dāng)我們通過(guò)主鍵來(lái)查詢的時(shí)候,比如id=6的條件,就是通過(guò)這顆B+樹(shù)來(lái)查找數(shù)據(jù)的過(guò)程。它先找到根頁(yè)面(page offset=3),然后通過(guò)二分查找,定位到id=6的數(shù)據(jù)在指針為5的頁(yè)上。然后進(jìn)一步的去page offset=5的頁(yè)面上加載數(shù)據(jù)。
在這里,我們需要理解兩件事:
上圖中B+樹(shù)的根節(jié)點(diǎn)(page offset=3),是固定不會(huì)變化的。只要表創(chuàng)建了聚簇索引,它的根節(jié)點(diǎn)頁(yè)號(hào)就被記錄到某個(gè)地方了。還有一點(diǎn),B+樹(shù)索引本身并不能直接找到具體的一條記錄,只能知道該記錄在哪個(gè)頁(yè)上,數(shù)據(jù)庫(kù)會(huì)把頁(yè)載入到內(nèi)存,再通過(guò)二分查找定位到具體的記錄。
現(xiàn)在我們知道了InnoDB存儲(chǔ)引擎最小存儲(chǔ)單元是頁(yè),在B+樹(shù)索引結(jié)構(gòu)里,頁(yè)可以放一行一行的數(shù)據(jù)(葉子節(jié)點(diǎn)),也可以放主鍵+指針(非葉子節(jié)點(diǎn))。
上面已經(jīng)說(shuō)過(guò),假如一行數(shù)據(jù)大小是1k,那么理論上一頁(yè)就可以放16條數(shù)據(jù)。那一頁(yè)可以放多少主鍵+指針呢?
假如我們的主鍵id為bigint類(lèi)型,長(zhǎng)度為8字節(jié),而指針大小在InnoDB源碼中設(shè)置為6字節(jié)。這樣算下來(lái)就是 16384 / 14 = 1170,就是說(shuō)一個(gè)頁(yè)上可以存放1170個(gè)指針。
一個(gè)指針指向一個(gè)存放記錄的頁(yè),一個(gè)頁(yè)里可以放16條數(shù)據(jù),那么一顆高度為2的B+樹(shù)就可以存放 1170 * 16=18720 條數(shù)據(jù)。同理,高度為3的B+樹(shù),就可以存放 1170 * 1170 * 16 = 21902400 條記錄。
理論上就是這樣,在InnoDB存儲(chǔ)引擎中,B+樹(shù)的高度一般為2-4層,就可以滿足千萬(wàn)級(jí)數(shù)據(jù)的存儲(chǔ)。查找數(shù)據(jù)的時(shí)候,一次頁(yè)的查找代表一次IO,那我們通過(guò)主鍵索引查詢的時(shí)候,其實(shí)最多只需要2-4次IO就可以了。
那么,實(shí)際上到底是不是這樣呢?我們接著往下看。
頁(yè)的類(lèi)型
在開(kāi)始驗(yàn)證之前,我們不僅需要了解頁(yè),還需要知道,在InnoDB引擎中,頁(yè)并不是只有一種。常見(jiàn)的頁(yè)類(lèi)型有:
- 數(shù)據(jù)頁(yè),B-tree Node;
- undo頁(yè),undo Log Page;
- 系統(tǒng)頁(yè),System Page;
- 事務(wù)數(shù)據(jù)頁(yè),Transaction system Page;
- 插入緩沖位圖頁(yè),Insert Buffer Bitmap;
- 插入緩沖空閑列表頁(yè),Insert Buffer Free List;
- 未壓縮的二進(jìn)制大對(duì)象頁(yè),Uncompressed BLOB Page;
在這里我們重點(diǎn)來(lái)看 B-tree Node,我們的索引和數(shù)據(jù)就放在這種頁(yè)上。既然有不同的頁(yè)類(lèi)型,我們?cè)趺粗喇?dāng)前的頁(yè)屬于什么頁(yè)呢?
那么我們就需要大概了解下數(shù)據(jù)頁(yè)的結(jié)構(gòu),數(shù)據(jù)頁(yè)由七個(gè)部分組成,每個(gè)部分都有不同的含義。
- File Header,文件頭,固定38字節(jié);
- Page Header,頁(yè)頭,固定56字節(jié);
- Infimum + supremum,固定26字節(jié);
- User Records,用戶記錄,即行記錄,大小不固定;
- Free Space,空閑空間,大小不固定;
- Page Directort,頁(yè)目錄,大小不固定;
- File Trailer,文件結(jié)尾信息,固定8字節(jié)。
其中,F(xiàn)ile Header用來(lái)記錄頁(yè)的一些頭信息,共占用38個(gè)字節(jié)。在這個(gè)頭信息里,我們可以獲取到該頁(yè)在表空間里的偏移值和這個(gè)數(shù)據(jù)頁(yè)的類(lèi)型。
接下來(lái)是Page Header,它記錄的是數(shù)據(jù)頁(yè)的狀態(tài)信息,共占用56個(gè)字節(jié)。在這一部分,我們可以獲取到兩個(gè)重要的信息:該頁(yè)中記錄的數(shù)量和當(dāng)前頁(yè)在索引樹(shù)的層級(jí),其中0x00代表葉子節(jié)點(diǎn),比如聚簇索引中的葉子節(jié)點(diǎn)放的就是整行數(shù)據(jù),它總是在第0層。
驗(yàn)證
前面我們已經(jīng)說(shuō)過(guò),ibd文件就是表數(shù)據(jù)文件。這個(gè)文件會(huì)隨著數(shù)據(jù)庫(kù)表里數(shù)據(jù)的增長(zhǎng)而增長(zhǎng),不過(guò)它始終會(huì)是16k的整數(shù)倍。里面就是一個(gè)個(gè)的頁(yè),那我們就可以一個(gè)一個(gè)頁(yè)的來(lái)解析,通過(guò)文件頭可以判斷它是什么頁(yè),找到 B-tree Node,就可以看到里面的 Page Level,它的值+1,就代表了當(dāng)前B+樹(shù)的高度。
我們現(xiàn)在就來(lái)重新創(chuàng)建一個(gè)表,為了使這個(gè)表中的數(shù)據(jù)一行大小為1k,我們?cè)O(shè)置幾個(gè)char(255)的字段即可。
CREATE?TABLE?`t5`?(
??`id`?bigint(8)?NOT?NULL,
??`c1`?char(245)?NOT?NULL?DEFAULT?'1',
??`c2`?char(255)?NOT?NULL?DEFAULT?'1',
??`c3`?char(255)?NOT?NULL?DEFAULT?'1',
??`c4`?char(255)?NOT?NULL?DEFAULT?'1',
??PRIMARY?KEY?(`id`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;
然后筆者寫(xiě)了一個(gè)存儲(chǔ)過(guò)程,用來(lái)批量插入數(shù)據(jù)用的,為了加快批量插入的速度,筆者還修改了innodb_flush_log_at_trx_commit=0,切記生產(chǎn)環(huán)境可不要這樣玩。
BEGIN
????DECLARE?i?int?DEFAULT?0;
????select?ifnull(max(id),0)?into?i?from?t5;
????set?i?=?i+1;
????WHILE?i?<=?100000?DO
????????insert?into?t5(id)value(i);
????????set?i?=?i+1;
????END?WHILE;
END
innodbPageInfo.jar是筆者用Java代碼寫(xiě)的一個(gè)工具類(lèi),用來(lái)輸出ibd文件中,頁(yè)的信息。
-path 后面是文件的路徑,-v 是否顯示頁(yè)的詳情信息,0是 1否。
上面我們創(chuàng)建了t5這張表,一條數(shù)據(jù)還沒(méi)有的情況下,我們看一下這個(gè)ibd文件的信息。
[root@localhost?innodbInfo]#?java?-jar?innodbPageInfo.jar?-path?/var/lib/mysql/test/t5.ibd?-v?0
page?offset?00000000,page?type?<File?Space?Header>
page?offset?00000001,page?type?<Insert?Buffer?Bitmap>
page?offset?00000002,page?type?<File?Segment?inode>
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0000>
page?offset?00000000,page?type?<Freshly?Allocated?Page>
page?offset?00000000,page?type?<Freshly?Allocated?Page>
數(shù)據(jù)頁(yè)總記錄數(shù):0
Total?number?of?page:?6
Insert?Buffer?Bitmap:?1
File?Segment?inode:?1
B-tree?Node:?1
File?Space?Header:?1
Freshly?Allocated?Page:?2
[root@localhost?innodbInfo]#?
t5表現(xiàn)在沒(méi)有任何數(shù)據(jù),它的ibd文件大小是98304,也就是說(shuō)一共有6個(gè)頁(yè)。其中第四個(gè)頁(yè)(page offset 3)是數(shù)據(jù)頁(yè),page level等于0,代表該頁(yè)為葉子節(jié)點(diǎn)。因?yàn)槟壳斑€沒(méi)有數(shù)據(jù),可以認(rèn)為B+樹(shù)的索引只有1層。
我們接著插入10條數(shù)據(jù),這個(gè)page level還是為0,B+樹(shù)的高度還是1,這是因?yàn)橐粋€(gè)頁(yè)大約能存放16條大小為1k的數(shù)據(jù)。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0000>
數(shù)據(jù)頁(yè)總記錄數(shù):10
Total?number?of?page:?6
當(dāng)我們插入15條數(shù)據(jù)的時(shí)候,一個(gè)頁(yè)就放不下了,原本為新分配的頁(yè)(Freshly Allocated Page)就會(huì)變成數(shù)據(jù)頁(yè),原來(lái)的根頁(yè)面(page offset=3)就會(huì)升級(jí)成存儲(chǔ)目錄項(xiàng)的頁(yè)。offset 04 和 05就變成了葉子節(jié)點(diǎn)的數(shù)據(jù)頁(yè),所以現(xiàn)在整個(gè)B+樹(shù)的高度為2。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0001>
page?offset?00000004,page?type?<B-tree?Node>,page?level?<0000>
page?offset?00000005,page?type?<B-tree?Node>,page?level?<0000>
數(shù)據(jù)頁(yè)總記錄數(shù):15
Total?number?of?page:?6
繼續(xù)插入10000條數(shù)據(jù),我們?cè)賮?lái)看一下B+樹(shù)高的情況。當(dāng)然現(xiàn)在信息比較多了,我們把輸出結(jié)果寫(xiě)到文件里。
java -jar innodbPageInfo.jar -path /var/lib/mysql/test/t5.ibd -v 0 > t5.txt
截取部分結(jié)果如下:
[root@localhost?innodbInfo]#?vim?t5.txt?
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0001>
page?offset?00000004,page?type?<B-tree?Node>,page?level?<0000>
page?offset?00000005,page?type?<B-tree?Node>,page?level?<0000>
page?offset?00000000,page?type?<Freshly?Allocated?Page>
數(shù)據(jù)頁(yè)總記錄數(shù):10000
Total?number?of?page:?1216
B-tree?Node:?716
可以看到,1萬(wàn)條1k大小的記錄,一共用了716個(gè)數(shù)據(jù)頁(yè),根頁(yè)面顯示的樹(shù)高還是2層。
前面我們計(jì)算過(guò),2層的B+樹(shù)理論上可以存放18000條左右,筆者測(cè)試大約13000條數(shù)據(jù)左右,B+樹(shù)就會(huì)成為3層了。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0002>
數(shù)據(jù)頁(yè)總記錄數(shù):13000
Total?number?of?page:?1472
B-tree?Node:?933
原因也不難理解,因?yàn)槊總€(gè)頁(yè)不可能只放數(shù)據(jù)本身。
首先每個(gè)頁(yè)都有一些固定的格式,比如文件頭部、頁(yè)面頭部、文件尾部這些,我們的數(shù)據(jù)放在用戶記錄這部分里的;
其次,用戶記錄也不只放數(shù)據(jù)行,每個(gè)數(shù)據(jù)行還有一些其他標(biāo)記,比如是否刪除、最小記錄、記錄數(shù)、在堆中的位置信息、記錄的類(lèi)型、下一條記錄的相對(duì)位置等等;
另外,MySQL參考手冊(cè)中也有說(shuō)到,InnoDB會(huì)保留頁(yè)的1/16空閑,以便將來(lái)插入或者更新索引使用,如果主鍵id不是順序插入的,那可能還不是1/16,會(huì)占用更多的空閑空間。
總之,我們理解一個(gè)頁(yè)不會(huì)全放數(shù)據(jù)就行了。所以,實(shí)測(cè)跟理論上不一致也是完全正常的,因?yàn)樯厦娴睦碚摏](méi)有排除這些項(xiàng)。
接著來(lái),我們?cè)俨迦?000萬(wàn)條數(shù)據(jù),現(xiàn)在ibd文件已經(jīng)達(dá)到11GB。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0002>
數(shù)據(jù)頁(yè)總記錄數(shù):10000000
Total?number?of?page:?725760
B-tree?Node:?715059
我們看到,1千萬(wàn)條數(shù)據(jù),數(shù)據(jù)頁(yè)已經(jīng)有71萬(wàn)個(gè),B+樹(shù)的高度還是3層,這也就是說(shuō)幾萬(wàn)條數(shù)據(jù)和一千萬(wàn)條數(shù)據(jù)的查詢效率基本上是一樣的。比如我們現(xiàn)在根據(jù)主鍵ID查詢一條數(shù)據(jù),select * from t5 where id = 6548215; ,查詢時(shí)間顯示用了0.010秒。
什么時(shí)候會(huì)到4層呢?大概在1300萬(wàn)左右,B+樹(shù)就會(huì)增加樹(shù)高到4層。
什么時(shí)候會(huì)到5層呢?筆者沒(méi)測(cè)試出來(lái),因?yàn)椴迦氲?000萬(wàn)條數(shù)據(jù)的時(shí)候,ibd數(shù)據(jù)文件大小已經(jīng)55G了,虛擬機(jī)已經(jīng)空間不足了。。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0003>
數(shù)據(jù)頁(yè)總記錄數(shù):50000000
B-tree?Node:?3575286
即便是5000萬(wàn)條數(shù)據(jù),我們通過(guò)主鍵ID查詢,查詢時(shí)間也是毫秒級(jí)的。
理論上要達(dá)到十億 - 百億行數(shù)據(jù),樹(shù)高才能到5層。如果有小伙伴用這種方法,測(cè)試出來(lái)5層高的數(shù)據(jù),歡迎在評(píng)論區(qū)留言,讓我看看。
另外,朋友們有沒(méi)有意識(shí)到一個(gè)問(wèn)題?其實(shí)影響B(tài)+樹(shù)樹(shù)高的因素,不僅是數(shù)據(jù)行,還有主鍵ID的長(zhǎng)度。我們上面的測(cè)試中,ID的類(lèi)型是bigint(8),在其他字段長(zhǎng)度均不變的情況下,我們把ID的類(lèi)型改為int(4),相同的樹(shù)高就會(huì)容納更多的數(shù)據(jù),因?yàn)樗鼏蝹€(gè)頁(yè)能承載的指針數(shù)變多了。
CREATE?TABLE?`t6`?(
??`id`?int(4)?NOT?NULL,
??`c1`?char(245)?NOT?NULL?DEFAULT?'1',
??`c2`?char(255)?NOT?NULL?DEFAULT?'1',
??`c3`?char(255)?NOT?NULL?DEFAULT?'1',
??`c4`?char(255)?NOT?NULL?DEFAULT?'1',
??PRIMARY?KEY?(`id`)
)?ENGINE=InnoDB?DEFAULT?CHARSET=utf8mb4;
針對(duì)t6這張表,我們插入16000條數(shù)據(jù),然后輸出一下頁(yè)面信息。
page?offset?00000003,page?type?<B-tree?Node>,page?level?<0001>
數(shù)據(jù)頁(yè)總記錄數(shù):16000
B-tree?Node:?1145
我們來(lái)看,如果按照主鍵ID類(lèi)型bigint(8)來(lái)測(cè)試,13000條數(shù)據(jù)的時(shí)候,樹(shù)高就已經(jīng)是3了,現(xiàn)在改為int(4),16000條數(shù)據(jù),樹(shù)高依然還是2層。盡管數(shù)據(jù)頁(yè)(B-tree Node)數(shù)量還是那么多,變化并不大,但是它不影響樹(shù)高。
ok,看到這里,相信朋友們對(duì)開(kāi)頭提出的問(wèn)題已經(jīng)有自己的答案了,如果你也跟著試一遍,理解可能會(huì)更加深入。
看到這,還有道經(jīng)典的面試題:為什么MySQL的索引要使用B+樹(shù)而不是其它樹(shù)形結(jié)構(gòu)?比如B樹(shù)?
簡(jiǎn)單來(lái)說(shuō),其中有一個(gè)原因就是B+樹(shù)的高度比較穩(wěn)定,因?yàn)樗姆侨~子節(jié)點(diǎn)不會(huì)保存數(shù)據(jù),只保存鍵值和指針的情況下,一個(gè)頁(yè)能承載大量的數(shù)據(jù)。你想啊,B樹(shù)它的非葉子節(jié)點(diǎn)也會(huì)保存數(shù)據(jù)的,同樣的一行數(shù)據(jù)大小是1kb,那么它一頁(yè)最多也只能保存16個(gè)指針,在大量數(shù)據(jù)的情況下,樹(shù)高就會(huì)速度膨脹,導(dǎo)致IO次數(shù)就會(huì)很多,查詢就會(huì)變得很慢。
源碼地址
本文的innodbPageInfo.jar代碼是筆者參考 MySQL技術(shù)內(nèi)幕(InnoDB存儲(chǔ)引擎)一書(shū)中的工具包,書(shū)里作者是用Python寫(xiě)的,所以筆者在這里用Java重新實(shí)現(xiàn)了一遍。
Java版本的源碼我放在GitHub上了:https://github.com/taoxun/innodbPageInfo
已經(jīng)打完包的Jar版本,也可以下載:https://pan.baidu.com/s/1IZVJRNUk_bPESp5zoQwOvA 提取碼:5rnz。
朋友們可以拿這個(gè)工具看一看,自己認(rèn)為較大的表,它的B+樹(shù)索引到底有幾層?
參考資料:
姜承堯:《MySQL技術(shù)內(nèi)幕:InnoDB存儲(chǔ)引擎》
天涯淚小武:https://tianyalei.blog.csdn.net/article/details/100015840
飄揚(yáng)的紅領(lǐng)巾:https://www.cnblogs.com/leefreeman/p/8315844.html
MySQL官方參考手冊(cè):https://dev.mysql.com/doc/refman/5.7/en/
