InnoDB存儲引擎的最小儲存單元是 頁(Page)
,一個頁的大小是默認是 16K
。磁盤存儲數據最小單元是 扇區
,一個扇區的大小是 512字節
, 而文件系統(例如XFS/EXT4)它的最小單元是 塊
,一個塊的大小是 4k
。
因此InnoDB的所有數據文件(后綴為 .ibd 的文件),它的大小始終都是16384B(16k)的整數倍。

數據表中的數據都是存儲在頁中的,所以一個頁中能存儲多少行數據呢?假設一行數據的大小是1k,那么一個頁可以存放16行這樣的數據。
但是除了有 存放數據的頁
以外,還有 存放鍵值+指針(索引)的頁
,即B+樹中的非葉子節點,該頁存放鍵值和指向數據頁的指針,這樣的頁由N個(鍵值+指針)組成。當然它也是排好序的。 這樣的數據組織形式,我們稱為「索引組織表」。索引組織表通過非葉子節點的「二分查找法」以及指針確定數據在哪個頁中,進而在去數據頁中查找到需要的數據。
這里我們先假設B+樹高為2,即存在一個根節點和若干個葉子節點,沒有子頁節點,那么這棵B+樹的存放總記錄數為:根節點指針數*單個葉子節點記錄行數
。
那么現在我們需要計算出非葉子節點能存放多少指針,也就是存放多少索引?
我們假設主鍵ID為 bigint
類型,長度為8字節,而 指針大小在InnoDB源碼中設置為6字節
,這樣一共14字節。
我們一個頁中能存放多少這樣的單元,其實就代表有多少指針,即 16384/14=1170。一個頁能存放1170個索引
那么可以算出一棵高度為2的B+樹,能存放1170*16=18720條這樣的數據記錄。
根據同樣的原理我們可以算出一個高度為3的B+樹可以存放:1170(根存的記錄指針數據)✖1170(下一級每個節點存的記錄指針數據)✖16(每個葉子階段存的數據條數)=21902400 條這樣的記錄,即2100w量級。
所以在InnoDB中B+樹高度一般為1-3層,它就能滿足千萬級的數據存儲。
在查找數據時一次頁的查找代表一次 IO
,所以通過主鍵索引查詢通常只需要1-3次 IO
操作即可查找到數據,即使一個是千萬量級的表,也是很快的。
最后還有一個問題,如何得到InnoDB主鍵索引B+樹的高度?
在InnoDB的表空間文件中,約定 page number
為 3 的代表主鍵索引的根頁,而在根頁偏移量為 64 的地方存放了該B+樹的 page level
。
如果 page level
為1,樹高為2, page level
為2,則樹高為3。即B+樹的高度=page level + 1
首先,找到MySql數據庫物理文件存放位置:

使用hexdump工具,查看表空間文件指定偏移量上的數據:

page level 值是 1,那么 B+樹高度為 page level + 1 = 2