咱們在MySQL中的數據通常是放在磁盤中的,讀取數據的時候確定會有訪問磁盤的操做,磁盤中有兩個機械運動的部分,分別是盤片旋轉和磁臂移動。盤片旋轉就是咱們市面上所提到的多少轉每分鐘,而磁盤移動則是在盤片旋轉到指定位置之後,移動磁臂後開始進行數據的讀寫。那麼這就存在一個定位到磁盤中的塊的過程,而定位是磁盤的存取中花費時間比較大的一塊,畢竟機械運動花費的時候要遠遠大於電子運動的時間。當大規模數據存儲到磁盤中的時候,顯然定位是一個很是花費時間的過程,可是咱們能夠經過B樹進行優化,提升磁盤讀取時定位的效率。mysql
爲何B類樹能夠進行優化呢?咱們能夠根據B類樹的特色,構造一個多階的B類樹,而後在儘可能多的在結點上存儲相關的信息,保證層數(樹的高度)儘可能的少,以便後面咱們能夠更快的找到信息,磁盤的I/O操做也少一些,並且B類樹是平衡樹,每一個結點到葉子結點的高度都是相同,這也保證了每一個查詢是穩定的。程序員
特別地:只有B-樹和B+樹,這裏的B-樹是叫B樹,不是B減樹。沒有B減樹的。面試
如下摘自【程序員小灰】sql
一、根結點至少有兩個子女。 二、每一箇中間節點都包含k-1個元素和k個孩子,其中 m/2 <= k <= m 三、每個葉子節點都包含k-1個元素,其中 m/2 <= k <= m 四、全部的葉子結點都位於同一層。五、每一個節點中的元素從小到大排列,節點當中k-1個元素正好是k個孩子包含的元素的值域分劃。
下面以3階B樹開始學習mongodb
這棵樹中,重點看(2,6)節點。該節點有兩個元素2和6,又有三個孩子1,(3,5),8。其中1小於元素2,(3,5)在(2,6)之間,8大於(3,5),正好符合上面所列的特徵。數據庫
好比上面的3階B樹查詢數值5。數組
第1次IO:數據結構
第2次IO:性能
第3次IO:學習
第3次內存比較:
總結:每次深度加1就會進行一次磁盤IO的查詢,將當前高度的數據加到內存中,再進行數值比較。從中能夠看出相比大部分的查詢時間是花費在磁盤IO的速度上,因此要想提升性能就是將樹的高度足夠低,IO次數足夠少,這就是B樹的優點。
好比樹裏添加數值4 自頂向下查找4的節點位置,發現4應當插入到節點元素3,5之間
節點3,5已是兩元素節點,沒法再增長。父親節點 2, 6 也是兩元素節點,也沒法再增長。根節點9是單元素節點,能夠升級爲兩元素節點。因而拆分節點3,5與節點2,6,讓根節點9升級爲兩元素節點4,9。節點6獨立爲根節點的第二個孩子。
從圖中能夠看到,爲了插入一個元素,幾乎所有的位置都變化了,這就是B樹的自平衡(始終維持多路平衡)。
自頂向下查找元素11的節點位置。
刪除11後,節點12只有一個孩子,不符合B樹規範。所以找出12,13,15三個節點的中位數13,取代節點12,而節點12自身下移成爲第一個孩子。(這個過程稱爲左旋)
主要用於文件系統以及部分數據庫索引(MongoDB) 而Mysql是用B+樹的。
一個m階的B+樹具備以下幾個特徵:
一、有k個子樹的中間節點包含有k個元素(B樹中是k-1個元素),每一個元素不保存數據,只用來索引,全部數據都保存在葉子節點。 二、全部的葉子結點中包含了所有元素的信息,及指向含這些元素記錄的指針,且葉子結點自己依關鍵字的大小自小而大順序連接。 三、全部的中間節點元素都同時存在於子節點,在子節點元素中是最大(或最小)元素。
從上圖能夠發現每個父節點的元素都出如今子節點中,而且是子節點的最大(或最小)
從圖中能夠看到根節點元素8是字節點2,5,8的最大元素,也是葉子節點6,8的最大元素。根節點15是子節點11,15的最大元素,也是葉子節點13,15的最大元素。
B+樹的最大元素始終位於根節點當中。全部葉子節點包含了全量元素信息,而且每個葉子節點都帶有指向 下一個節點指針,造成了一個有序鏈表。
單個查詢:查詢某個元素3
第一次磁盤IO:
第二次磁盤IO:
第三次磁盤IO:
這樣看起來跟B樹沒有什麼區別。但其實有兩點是須要注意的:
一、B+樹的中間節點沒有衛星數據的。因此一樣大小的磁盤頁能夠容納更多的節點元素。(這就意味着B+會更加矮胖,查詢的IO次數會更少)
B樹的衛星數據
B+樹的衛星數據
二、B樹查找性能是不穩定的(若是要查找的數據分別在根節點和葉子節點,他們的性能就會不一樣)。但B+樹的每一次都是穩定的,爲啥呢,看下面的範圍查詢。
範圍查詢:查找到範圍的下限(3)
B樹的範圍查詢:
自頂向下,查找到範圍的下限(3),最多6條:
中序遍歷到元素6:
中序遍歷到元素8:
中序遍歷到元素9:
中序遍歷到元素11,遍歷結束:
B+樹的範圍查詢:
自頂向下,查找到範圍的下限(3),最多6條:
經過鏈表指針,遍歷到元素6, 8:
經過鏈表指針,遍歷到元素9, 11,遍歷結束:
從上面的流程比較,能夠得出如下B+樹的優點:
1.單一節點存儲更多的元素,使得查詢的IO次數更少。
2.全部查詢都要查找到葉子節點,查詢性能穩定。
3.全部葉子節點造成有序鏈表,便於範圍查詢。
問題1:MySQL中存儲索引用到的數據結構是B+樹,B+樹的查詢時間跟樹的高度有關,是log(n),若是用hash存儲,那麼查詢時間是O(1)。既然hash比B+樹更快,爲何mysql用B+樹來存儲索引呢?
答:1、從內存角度上說,數據庫中的索引通常時在磁盤上,數據量大的狀況可能沒法一次性裝入內存,B+樹的設計能夠容許數據分批加載。
2、從業務場景上說,若是隻選擇一個數據那確實是hash更快,可是數據庫中常常會選中多條這時候因爲B+樹索引有序,而且又有鏈表相連,它的查詢效率比hash就快不少了。
問題2:爲何不用紅黑樹或者二叉排序樹?
答:樹的查詢時間跟樹的高度有關,B+樹是一棵多路搜索樹能夠下降樹的高度,提升查找效率
問題3:既然增長樹的路數能夠下降樹的高度,那麼無限增長樹的路數是否是能夠有最優的查找效率?
答:這樣會造成一個有序數組,文件系統和數據庫的索引都是存在硬盤上的,而且若是數據量大的話,不必定能一次性加載到內存中。有序數組無法一次性加載進內存,這時候B+樹的多路存儲威力就出來了,能夠每次加載B+樹的一個結點,而後一步步往下找,
問題4:在內存中,紅黑樹比B樹更優,可是涉及到磁盤操做B樹就更優了,那麼你能講講B+樹嗎?
B+樹是在B樹的基礎上進行改造,它的數據都在葉子結點,同時葉子結點之間還加了指針造成鏈表。
下面是一個4路B+樹,它的數據都在葉子結點,而且有鏈表相連。
問題5:爲何B+樹要這樣設計?
答:這個跟它的使用場景有關,B+樹在數據庫的索引中用得比較多,數據庫中select數據,不必定只選一條,不少時候會選中多條,好比按照id進行排序後選100條。若是是多條的話,B樹須要作局部的中序遍歷,可能要跨層訪問。而B+樹因爲全部數據都在葉子結點不用跨層,同時因爲有鏈表結構,只須要找到首尾,經過鏈表就能把全部數據取出來了。
好比選出7到19只須要在葉子結點中就能找到。