MySQL索引(二)B+樹在磁盤中的存儲
回顧

上一篇文章《MySQL索引為什么要用B+樹》講了MySQL為什么選擇用B+樹來作為底層存儲結構,提了兩個知識點:
- B+樹索引並不能直接找到行,只是找到行所在的頁,通過把整頁讀入內存,再在內存中查找。
- 索引的B+樹高度一般為2-4層,查找記錄時最多只需要2-4次IO。
為進一步知其所以然,今天來聊聊B+樹索引在物理磁盤上是怎么設計存儲的。
一、理解為什么要減少磁盤IO次數
眾所周知,MySQL的數據實際是存儲在文件中,而磁盤IO的查找速度是要遠小於內存速度的,所以減少磁盤IO的次數能很大程度的提高MySQL性能。
1.1 磁盤IO為什么慢
先溫習下知識點:磁盤IO時間 = 尋道 + 磁盤旋轉 + 數據傳輸時間
從磁盤讀取數據時,系統會將邏輯地址發給磁盤,磁盤將邏輯地址轉換為物理地址(哪個磁道,哪個扇區)。 磁頭進行機械運動,先找到相應磁道,再找該磁道的對應扇區,扇區是磁盤的最小存儲單元(見圖1-1
)。

1.2 性能對比
機械硬盤的連續讀寫性能很好,但隨機讀寫性能很差。
- 順序訪問:內存訪問速度是硬盤訪問速度的6~7倍(
kafka
的特點,以后有機會的話再講一講) - 隨機訪問:內存訪問速度就要比硬盤訪問速度快上10萬倍以上
隨機讀寫時,磁頭需要不停的移動,時間都浪費在了磁頭尋址上。 而在實際的磁盤存儲里,是很少順序存儲的,因為這樣的維護成本會很高。
二、索引在磁盤上的存儲
知道磁盤IO的性能了吧,接下來看看MySQL是如何根據這種情況來設計索引的物理存儲,以下內容以InnoDB
引擎為例,MyISAM
略有不同,后面再講。
假設我們有一張這樣的表,表中有如圖2-0
的數據
CREATE TABLE `user` ( `ID` bigint(11) NOT NULL AUTO_INCREMENT, `NAME` varchar(20), PRIMARY KEY (`ID`), KEY `idx_name` (`NAME`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; 復制代碼

2.1 聚集索引(Clustered index )
每個InnoDB表都有一個稱為聚集索引的特殊索引,該索引是按照表的主鍵構造的一棵B+樹。
根據示例數據構建如圖2-1所示聚集索引:

2.1.1 知識點
- 葉子節點存放了整張表的所有行數據。
- 非葉子節點並不存儲行數據,是為了能存儲更多索引鍵,從而降低B+樹的高度,進而減少IO次數。
- 聚集索引的存儲在物理上並不是連續的,每個數據頁在不同的磁盤塊,通過一個雙向鏈表來進行連接。
2.1.2 查找:假設要查找數據項6
- 把根節點由磁盤塊0加載到內存,發生一次IO,在內存中用二分查找確定6在3和9之間;
- 通過指針P2的磁盤地址,將磁盤2加載到內存,發生第二次IO,再在內存中進行二分查找找到6,結束。
這里只進行了兩次IO,實際上,每個磁盤塊大小為4K,3層的B+樹可以表示上百萬的數據,也就是每次查找只需要3次IO,所以索引對性能的提高將是巨大的。

2.1.3 怎樣選擇聚集索引
每張InnoDB表有且只有一個聚集索引,那它是怎么選擇索引的呢?
- 一般情況,用
PRIMARY KEY
來作為聚集索引。 - 如果沒有定義
PRIMARY KEY
,將會用第一個UNIQUE
且NOT NULL
的列來作為聚集索引。 - 如果表沒有合適的
UNIQUE
索引,會內部根據行ID值生成一個隱藏的聚簇索引GEN_CLUST_INDEX
。
所以在建表的時候,如果沒有邏輯唯一且非空列時,可以添加一個auto_increment的列,方便建立一個聚集索引。
2.2 非聚集索引(Secondary indexes)
非聚集索引又叫輔助索引,葉子節點並不包含行記錄數據,而是存儲了聚集索引鍵。
根據示例數據(idx_name
索引)構建如圖2-2所示輔助索引:

2.2.1 知識點
- 每個表可以有多個輔助索引
- 通過輔助索引查數據時,先查找輔助索引獲得聚集索引的主鍵,然后通過主鍵索引來查找完整的行記錄。
- 通過非主鍵索引比主鍵索引查找速度要慢一倍。
2.2.2 查找:獲取NAME=Jake
的數據
第一階段:通過輔助索引查到主鍵索引的主鍵
- 把idx_name索引的根節點由磁盤塊0加載到內存,發生一次IO,查找到在P2指針中
- 根據P2指針的磁盤地址,加載磁盤塊2到內存,發生第二次IO,查找到Jake節點以及它的主鍵索引9
第二階段:通過主鍵索引找到完整的行記錄
- 把根節點由磁盤塊0加載到內存,發生一次IO,在內存中用二分查找確定9在P3指針中
- 通過指針P3的磁盤地址,將磁盤3加載到內存,發生第二次IO,再在內存中進行二分查找找到9,以及它的行記錄,
查找結束。
未完待續…
原文鏈接:MySQL索引(二)B+樹在磁盤中的存儲 - 掘金 https://juejin.im/post/5cef2c43e51d45572c05ffe3