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

回顧

w200

上一篇文章《MySQL索引爲何要用B+樹》講了MySQL爲何選擇用B+樹來做爲底層存儲結構,提了兩個知識點:sql

  1. B+樹索引並不能直接找到行,只是找到行所在的頁,經過把整頁讀入內存,再在內存中查找。
  2. 索引的B+樹高度通常爲2-4層,查找記錄時最多隻須要2-4次IO。

爲進一步知其因此然,今天來聊聊B+樹索引在物理磁盤上是怎麼設計存儲的。性能

1、理解爲何要減小磁盤IO次數

衆所周知,MySQL的數據實際是存儲在文件中,而磁盤IO的查找速度是要遠小於內存速度的,因此減小磁盤IO的次數能很大程度的提升MySQL性能。ui

1.1 磁盤IO爲何慢

先溫習下知識點:磁盤IO時間 = 尋道 + 磁盤旋轉 + 數據傳輸時間spa

從磁盤讀取數據時,系統會將邏輯地址發給磁盤,磁盤將邏輯地址轉換爲物理地址(哪一個磁道,哪一個扇區)。 磁頭進行機械運動,先找到相應磁道,再找該磁道的對應扇區,扇區是磁盤的最小存儲單元(見圖1-1)。設計

-w356
 圖1-1 磁盤物理結構

1.2 性能對比

機械硬盤的連續讀寫性能很好,但隨機讀寫性能不好。指針

  • 順序訪問:內存訪問速度是硬盤訪問速度的6~7倍(kafka的特色,之後有機會的話再講一講)
  • 隨機訪問:內存訪問速度就要比硬盤訪問速度快上10萬倍以上

隨機讀寫時,磁頭須要不停的移動,時間都浪費在了磁頭尋址上。 而在實際的磁盤存儲裏,是不多順序存儲的,由於這樣的維護成本會很高。code

2、索引在磁盤上的存儲

知道磁盤IO的性能了吧,接下來看看MySQL是如何根據這種狀況來設計索引的物理存儲,如下內容以InnoDB引擎爲例,MyISAM略有不一樣,後面再講。orm

假設咱們有一張這樣的表,表中有如圖2-0的數據cdn

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-0 表數據

2.1 彙集索引(Clustered index )

每一個InnoDB表都有一個稱爲彙集索引的特殊索引,該索引是按照表的主鍵構造的一棵B+樹。blog

根據示例數據構建如圖2-1所示彙集索引:

 圖2-1 B+樹彙集索引

2.1.1 知識點

  • 葉子節點存放了整張表的全部行數據。
  • 非葉子節點並不存儲行數據,是爲了能存儲更多索引鍵,從而下降B+樹的高度,進而減小IO次數。
  • 彙集索引的存儲在物理上並非連續的,每一個數據頁在不一樣的磁盤塊,經過一個雙向鏈表來進行鏈接。

2.1.2 查找:假設要查找數據項6

  1. 把根節點由磁盤塊0加載到內存,發生一次IO,在內存中用二分查找肯定6在3和9之間;
  2. 經過指針P2的磁盤地址,將磁盤2加載到內存,發生第二次IO,再在內存中進行二分查找找到6,結束。

這裏只進行了兩次IO,實際上,每一個磁盤塊大小爲4K,3層的B+樹能夠表示上百萬的數據,也就是每次查找只須要3次IO,因此索引對性能的提升將是巨大的。

2.1.3 怎樣選擇彙集索引

每張InnoDB表有且只有一個彙集索引,那它是怎麼選擇索引的呢?

  • 通常狀況,用PRIMARY KEY來做爲彙集索引。
  • 若是沒有定義PRIMARY KEY,將會用第一個UNIQUENOT NULL的列來做爲彙集索引。
  • 若是表沒有合適的UNIQUE索引,會內部根據行ID值生成一個隱藏的聚簇索引GEN_CLUST_INDEX

因此在建表的時候,若是沒有邏輯惟一且非空列時,能夠添加一個auto_increment的列,方便創建一個彙集索引。

2.2 非彙集索引(Secondary indexes)

非彙集索引又叫輔助索引,葉子節點並不包含行記錄數據,而是存儲了彙集索引鍵。

根據示例數據(idx_name索引)構建如圖2-2所示輔助索引:

 圖2-2 B+樹非彙集索引

2.2.1 知識點

  • 每一個表能夠有多個輔助索引
  • 經過輔助索引查數據時,先查找輔助索引得到彙集索引的主鍵,而後經過主鍵索引來查找完整的行記錄。
  • 經過非主鍵索引比主鍵索引查找速度要慢一倍。

2.2.2 查找:獲取NAME=Jake的數據

第一階段:經過輔助索引查到主鍵索引的主鍵

  1. 把idx_name索引的根節點由磁盤塊0加載到內存,發生一次IO,查找到在P2指針中
  2. 根據P2指針的磁盤地址,加載磁盤塊2到內存,發生第二次IO,查找到Jake節點以及它的主鍵索引9

第二階段:經過主鍵索引找到完整的行記錄

  1. 把根節點由磁盤塊0加載到內存,發生一次IO,在內存中用二分查找肯定9在P3指針中
  2. 經過指針P3的磁盤地址,將磁盤3加載到內存,發生第二次IO,再在內存中進行二分查找找到9,以及它的行記錄,

查找結束。


未完待續…

若是想要實時關注更新的文章以及分享的乾貨,能夠關注個人公衆號

懂了嗎
相關文章
相關標籤/搜索