B樹與B+樹區別辨析

數小錢錢的種花兔發表於2021-01-11

我們都知道,innodb中的索引結構使用的是B+樹。B+樹是一種B樹的變形樹,而B樹又是來源於平衡二叉樹。相較於平衡二叉樹,B樹更適合磁碟場景下檔案索引系統。那為什麼B樹更適合磁碟場景,B+樹又在B樹基礎上做了什麼優化?抱著這些問題,本部落格將深入分析B樹和B+樹來龍去脈,其中會涉及到二叉排序樹和平衡二叉樹等資料結構。

二叉排序樹、平衡二叉樹、B樹和B+樹都是基於二分法的思路來優化查詢的。

二叉排序樹

要談B樹,首先要理解平衡二叉樹。而平衡二叉樹又是從二叉排序樹優化而來。讓我們追根溯源先看看二叉排序樹。這個資料結構非常容易理解,滿足如下性質即為一棵二叉排序樹

  • 若左子樹不為空,則左子樹上所有結點值均小於它的根結點值;
  • 若右子樹不為空,則右子樹上所有結點值均大於等於它的根結點值;
  • 左右子樹也分別是二叉排序樹。

中序遍歷一棵二叉排序樹能得到一個遞增的有序序列

問題:二叉排序樹的查詢效能受限於它的結構,如果結構合理,複雜度能達到二分法的複雜度,O(log2N);而在極端情況下,往二叉排序樹中插入結點,會得到一個單連結串列,這樣時間複雜度就是O(N)了。樹的高度越小,查詢速度越快。

平衡二叉樹

為了使二叉排序樹高度儘可能小,平衡二叉樹誕生了,也成為AVL樹。這種資料結構,是具備如下特徵的二叉排序樹:

  • 左子樹和右子樹深度之差絕對值不超過1;
  • 左子樹和右子樹也是平衡二叉樹。

平衡二叉樹通過“旋轉”操作來保證左右子樹深度之差小於等於1,從而保證樹的高度儘可能小。

問題:雖說平衡二叉樹可以保證一定的查詢效率。即便這樣,平衡二叉樹方法也只適用於儲存在記憶體中的較小的檔案,如果是查詢存放在外存中很大的檔案,每訪問一個結點就需要進行磁碟IO,由於節點眾多,開銷依然很大。

B樹

既然結點太多了,那將多個結點合成一個節點如何,是否可以減少IO次數。這樣也相當於將二叉樹變成多叉樹。B樹也是基於這個思路來實現的,即一個結點包含多個關鍵字(表示要查詢的目標數值)和多個指向子樹的指標。
對於一個m階的B樹,擁有如下特性:

  • 樹中每個結點至多有m棵子樹;
  • 若根結點不是葉子結點,則至少有兩棵子樹;
  • 除了根結點以外的所有非終端結點,至少有m/2棵子樹;
  • 所有葉子結點都出現在同一層次上(這體現出平衡的特點),並且不帶資訊,成為失敗結點;
  • 所有非終端結點最多有m-1個關鍵字。

在實際的檔案系統場景中,B樹的結點規模一般以一個磁碟頁為單位,所以m值取決於磁碟頁大小

結點結構如下所示

image

第一個元素n記錄當前結點的關鍵字數量。K1 - Kn 表示各個關鍵字,P0 - Pn 表示指向子樹根結點的指標。重要性質:Pi所指向子樹中所有結點關鍵字均大於Ki,並且小於Ki+1。B樹便是依據此性質來完成查詢。

因此,B樹查詢的過程與平衡二叉樹類似,無需贅述。但是插入和刪除不太一樣。

插入

以插入為例,假設要向一個m階B樹插入某個關鍵字,B樹會先查詢該關鍵字在最底層的位置,向對應的位置插入。同時保證結點數量不超過m-1,如果超過數量限制,則會進行結點“分裂”,以中間關鍵字為界將結點一分為二,並將中間關鍵字向上插入到雙親結點上,若雙親結點已滿,用同樣的方法繼續分解,直到分解到根節點,此時B樹高度加1。

刪除

對於刪除而言,同理,如果結點的關鍵字刪除後數量小於(m/2)-1則要進行“合併”結點的操作。除了刪除關鍵字,還需要刪除關鍵字鄰近的指標。例如刪除Ki時,也需要刪除Pi。這裡就有兩種情況,若刪除的結點Pi是最低層,直接刪除Ki和Pi即可,因為指標指向null;如果不是,不能直接刪,因為Pi指向一棵子樹,這時需要將Pi指向的子樹裡最小的關鍵字與待刪除關鍵字互換,互換之後目標關鍵字一定是轉移到了最低一層,將其和相鄰指標刪除即可。

B+樹

B樹已經是很優秀的資料結構了,為什麼還需要B+樹呢?先來看看二者的區別。B+樹是B樹的變形樹,它們的差異如下:

  • 有n棵子樹的結點中含有n個關鍵字;
  • 所有葉子結點中包含全部關鍵字資訊,以及指向含有這些關鍵字記錄的指標,且葉子結點本身依關鍵字的大小自小而大順序連結;
  • 所有非終端結點可以看成是索引部分,結點中僅含有其子樹中的最大或最小關鍵字(innodb中是最小關鍵字)

B+樹的隨機查詢、插入和刪除過程基本與B樹類似

與B樹相比的優勢

1.查詢的IO次數更少

其實上文在B樹中提到的關鍵字,不僅僅只是數值,也包含具體的資料。讀取結點,也會把各個關鍵字對應的具體資料讀取出來。而在B+樹中對於非終端節點而言,每一個關鍵字只是一個索引,不包含其它資料(只有終端結點才會引用具體資料)。因此,在單個結點大小一致的前提下(取磁碟頁的大小),B+樹中每個非終端結點結點可以儲存更多元素,因此樹的分支會更多,更加矮胖,查詢的IO次數也更少。

2.查詢效能穩定

B樹查詢不同結點效能可能不一樣,因為目標元素可能位於根節點,也可能在葉子結點上。但是B+樹中有效結點一定在最低層,所以每次查詢必須查到葉子結點,效能穩定。

3.便於範圍查詢

範圍查詢,B樹需要進行多次二分查詢。而B+樹只需要一次二分查詢找到下限,之後再順著連結串列找到上限即可。葉子結點通過連結串列互相連線這一事實,決定了B+樹在範圍查詢上的優勢。

綜上所述,在MySQL索引結構中使用B+樹效能要更優於B樹。

相關文章