索引的底層原理——B樹,B+樹

  在文件存儲系統中,會使用到B樹來進行存儲,爲什麼要這樣做?這樣做的原因是什麼?

  如果我們在很多數據中去查詢一條數據,逐一進行比較是最容易想到的辦法,逐一進行比較的算法時間複雜度是O(n),似乎是慢了點。這時我們就想到了AVL樹,這種數據結構的搜索時間複雜度是O(logn),也就是說對數據進行排序,然後使用二分搜索的思路進行查找,時間複雜度當然就是O(logn),那麼使用AVL樹就可以了,爲什麼要引進B樹,先來了解一下B樹

  首先,B樹也是一棵二叉搜索樹,只不過是m階搜索樹,有以下幾個性質:

1.樹中的每個節點最多有m個孩子
2.除根節點和葉子節點的節點孩子數至少爲ceil(m/2)
3.除根節點外的關鍵字數至少爲 ceil(m/2)-1<=關鍵字<=m-1
注:ceil爲取上限函數

剛看到這幾個特點,或許不明白爲什麼孩子數和關鍵字數至少這麼多,我們先來看看B樹的插入操作,然後再來進行解釋

B樹的插入

舉例說明,在5階B樹種插入一組字母:
C N G A H E K Q M F W L T Z D P R X Y S
注意,插入同樣需要遵循搜索二叉樹的性質,小的在左邊,大的在右邊,插入前5個

在這裏插入圖片描述
由於是5階,節點的關鍵字最多爲4,所以需要向上分裂,即把G提上去,AC和HN分別爲左右孩子
在這裏插入圖片描述
插入E,K,N,找到合適的位置,如下圖:
在這裏插入圖片描述
插入M時,發現插入的節點已經滿足了5個,這時對該節點向上分裂
在這裏插入圖片描述
找到相應的位置,插入F,W,L,T
在這裏插入圖片描述
插入Z,發現插入的節點後爲NQTWZ,已經滿足了5個,所以需要向上分裂,如下圖
在這裏插入圖片描述
插入D,當前節點爲ACDEF,需要向上分裂,分裂後如下圖:
在這裏插入圖片描述
插入P,R,X,Y
在這裏插入圖片描述
插入S,當前節點變爲NPQRS,Q向上分裂,分裂完如下圖:
在這裏插入圖片描述
這時發現根節點已經5個了,DGMQT,需要繼續分裂,把M提上去
在這裏插入圖片描述
  這樣就完成了M的插入,後面的就不在繼續畫圖了,到這裏我們也就明白了B樹是絕對平衡的,正是由於他向上分裂的結果。總結一下節點的插入過程,當插入的節點沒有滿的時候,直接插入到當前節點中,當插入的節點滿了以後,當前節點就需要向上分裂,分裂後父節點相當於插入了一個新的關鍵字,如果未滿,則直接插入,如果滿了,則繼續向上迭代。

  在這裏解釋一下B樹第二,三條性質。當向上分裂時,關鍵字首先會減一,也就是向上分裂了,然後分一半就是節點的關鍵字至少多少,如果原來節點的關鍵字個數是m個,分裂後爲(m-1)/2,這裏是取下限,如果改爲取上限,就是ceil(m/2)-1,兩者結果完全相同。如果關鍵字個數至少爲ceil(m/2)-1,那麼孩子數就比關鍵字個數多1,即ceil(m/2)

在這裏插入圖片描述
上圖是B樹的圖,藍色表示關鍵字,黃色表示孩子,而紅色則是與關鍵字進行綁定的數據行,現在來解釋一下爲什麼AVL可以完成的事情,爲什麼需要B樹來完成:
  在每一次比對查詢是否正確的時候,因爲數據量大,都是存在於磁盤上的,所以每次調取數據都需要完成一次磁盤IO,在操作系統層面來講,內存中是以頁爲單位,磁盤是以塊爲單位,不論每次進行磁盤IO的數據量大小,最小都要以一個數據塊爲單位,這就造成了浪費,B樹的高度會非常低,也就是說高度爲幾,則需要進行幾次磁盤IO,真實環境中有可能時幾百階的B樹,這樣就保證了一次磁盤IO會充分利用好一個單位塊數據。總結來說,採用B樹,而不是AVL樹,就是爲了減少磁盤IO的次數,減少浪費。

但是在實際過程中,採用的是B+樹,是B樹的進化版,B+樹如下圖所示:
在這裏插入圖片描述
同樣,藍色是關鍵字,黃色是孩子,紅色是與關鍵字綁定的數據行,會發現B+樹有幾個與B樹不同的特點:

  1. 數據都出現在葉子節點,所以拿到數據的時間是相同的。樹幹節點就是用於搜索
  2. 有一個鏈表串起了整張數據表,這樣更利於範圍查詢

那麼B+樹相對於B樹的查詢優勢有以下三點:

  1. 由於非葉子節點的關鍵字只用於搜索,不存儲數據行地址,那麼同一個塊中能容納的關鍵字就越多,樹的高度就越矮,查詢的效率就越高
  2. 由於數據行地址都是在葉子節點中,所以查詢的時間比較穩定
  3. 由於鏈表指針的存在,所以更利於範圍查詢
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章