Mysql 索引為什么要用B+數


說點題外的:

MySQL當中的 “My” 是什么意思?

MySQL的發明者名叫 Michael “Monty” Widenius,MySQL是以他女兒的名字 “My” 來命名的。對這位發明者來說,MySQL數據庫就仿佛是他可愛的女兒。

她的二女兒叫什么呢?二女兒叫Maria,MariaDB名字的來源。

正題:

在從一堆數據中查找指定的數據時,我們常用的數據結構是哈希表和二叉查找樹,表本質上就是一堆數據的集合,所以MySQL數據庫用了哈希表和B+樹來實現索引

B+樹是通過二叉查找樹,再由平衡二叉樹,B樹(又名B-樹)演化而來的,B+樹中的B不是代表二叉(binary),而是代表平衡(balance),因為B+樹是從最早的平衡二叉樹演化而來,但是B+樹不是一個二叉樹。

二叉查找樹

二叉查找樹是帶有特殊屬性的二叉樹,需要滿足以下屬性

  1. 非葉子節點最多擁有兩個子節點
  2. 非葉子節值大於左邊子節點、小於右邊子節點(左小右大)
  3. 沒有值相等重復的節點;

 

 

 

對上圖這個二叉樹進行查找,如查鍵值為5的記錄,先找到根,其值時6,大於5,查找6的左子樹,找到4,4小於5,再找其右子樹,一共找了3次。同理,查找鍵值為8的記錄,用了1次。所有鍵值平均查找次數為(1+2+2+3+3+3)/6=2.3次,假如對這些鍵值進行順序查找,平均查找次數為(1+2+3+4+5+6)/6=3.3(查找順序擺放的數,第一個數肯定是1次,而第2個數是2次,以此類推),顯然二叉查找樹的平均查找速度比順序查找更快
二叉查找樹可以任意的構造,假如二叉查找樹按照如下方式構造

 

 

 平均查找速度為(1+2+3+4+5+5)/6=3.16次,和順序查找差不多。為了提高二叉查找樹的查詢效率,需要二叉查找數是平衡的,這就引出了平衡二叉樹。

平衡二叉樹:

平衡二叉樹除了滿足上面3個屬性,還要滿足如下1個屬性

  1. 樹的左右兩邊的層級數相差不會大於1

平衡二叉樹的查找效率確實很快,但維護一顆平衡二叉樹的代價是非常大的,需要1次或多次左旋和右旋來得到插入或更新后樹的平衡性。左旋右旋就是選定一個節點作為目標節點,此目標節點就變成左節點/右節點

舉個栗子:

有一個x節點,對x進行左旋意味着將x變為一個左節點

 

 

 

 

同理有一個y節點,對y進行右旋意味着將y變為一個右節點

 

 

 

 

 

 

 

 

B樹和B+樹

B樹和B-樹是同一種樹,假如用平衡二叉樹實現索引效率已經很高了,查找一個節點所做的IO次數是這個節點所處的樹的高度,因為我們無法把整個索引都加載到內存,並且節點數據在磁盤中不是順序排放的。所以最快情況下,磁盤的IO次數為數的高度。

雖然平衡二叉樹查找效率確實很高,但是頻繁的IO才是阻礙提高性能的瓶頸,怎樣減少IO次數呢?前輩們很聰明的提出了局部性原理,分為時間局部性原理,即加入你查詢id為1的用戶數據,過一段時間你還會查詢id為1的數據,所以會將這部分數據緩存下來。空間局部性原理,當你查詢id為1的用戶數據的時候,你有很大的概率會去查詢id為2,3,4的用戶的數據,所以會一次性的把id為1,2,3,4的數據都讀到內存中去,這個最小的單位就是頁。

借用別人的圖展示下

簡單來說CPU進行運算是電子運動,計算速度很快。而將數據從硬盤讀取到內存中是機械運動,很慢。我們在買硬盤的時候經常問這個硬盤是多少轉(每分鍾轉動的圈數),7200轉,5400轉。所以說轉動的越快加載數據越快,但是和CPU比起來差的還很遠,所以說要減低IO次數。

B樹和B+樹的區別:

B+跟B樹不同B+樹的非葉子節點不保存鍵值對應的數據,這樣使得B+樹每個節點所能保存的鍵值大大增加;
B+樹葉子節點保存了父節點的所有鍵值和鍵值對應的數據,每個葉子節點的關鍵字從小到大鏈接;
B+樹的根節點鍵值數量和其子節點個數相等;
B+的非葉子節點只進行數據索引,不會存實際的鍵值對應的數據,所有數據必須要到葉子節點才能獲取到,所以每次數據查詢的次數都一樣;

B樹

 

 

 B+樹

 

 

 

在B樹的基礎上每個節點存儲的關鍵字數更多,樹的層級更少所以查詢數據更快,所有關鍵字指針都存在葉子節點,所以每次查找的次數都相同所以查詢速度更穩定。除此之外,B+樹的葉子節點是跟后序節點相連接的,這對范圍查找是非常有用的。

B+樹的非葉子節點是主鍵,主鍵占用的空間越小,每個節點能放的主鍵就能更多,這就是為什么我們的主鍵一般不設置太大的原因。主鍵占用的空間小,能降低樹高,減少IO次數。

聚集索引和聯合索引

在InnoDB存儲引擎中,是以主鍵為索引來組織數據的。在InnoDB存儲引擎中,每張表都有個主鍵,如果再創建表時沒有顯示的定義主鍵,則InnoDB存儲引擎會按如下方式選擇或創建主鍵。

首先判斷表中是否有非空的唯一索引,如果有,則該列即為主鍵
如果不符合上述條件,InnoDB存儲引擎自動創建一個6字節大小的指正作為索引
如果有多個非空唯一索引時,InnoDB存儲引擎將選擇建表時第一個定義的非空唯一索引作為主鍵
假如說有如下數據,用戶id為主鍵(1, jack),(2,mike),(3,tom),(4,apple),(5,angle)則數據是這樣存儲的 如圖一

 

 

 假如說我們現在對用戶名建索引,用戶名索引是怎么存的呢 如圖二

 

 用戶名索引主鍵存儲的是主鍵,所以當我們運行如下sql語句時

select * from table_name where name ="jack"

過程是這樣的,先在name索引上找到對應的主鍵,在根據對應的主鍵去建表時建立的B+樹上找到對應的記錄,即先在圖2上找,再到圖1上找。

聚集索引:數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。圖1用的就是聚集索引

非聚集索引:定義:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。圖2用的就是非聚集索引
多個鍵值得B+樹是如下存儲的

 

 

可以看到鍵值都是排序的,就上面的例子來說(1,1)(1,2)(2,1)(2,4)(3,1)(3,2),數據按照(a,b)的順序進行了存放。

因此對於查詢select * from table where a = xxx and b = xxx,顯然是可以使用(a,b)這個聯合索引的。對於單個的a列查詢select * from table where a = xxx,也可以使用(a,b)這個索引。但對於b列的查詢select * from table where b = xxx,則不可以使用這顆B+樹索引。可以發現葉子節點上的b值為1,2,1,4,1,2,顯然不是排序的,因此對於b列的查詢使用不到(a,b)的索引

那么為什么mysql索引要用b+樹原因如下:

  1. B+樹能顯著減少IO次數,提高效率
  2. B+樹的查詢效率更加穩定,因為數據放在葉子節點
  3. B+樹能提高范圍查詢的效率,因為葉子節點指向下一個葉子節點

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM