基於磁盤IO角度來看二叉樹、B-tree樹、B+樹


轉載自波波說運維

概述

前面已經介紹了B-TREE的相關內容,所以這里對其架構就不多做介紹了,主要是從磁盤IO的角度來看,看一下為什么要用B樹。


相關概念

B樹這種數據結構常常用於實現數據庫索引,因為它的查找效率比較高。

1、磁盤IO與預讀

磁盤讀取依靠的是機械運動,分為尋道時間、旋轉延遲、傳輸時間三個部分,這三個部分耗時相加就是一次磁盤IO的時間,大概9ms左右。這個成本是訪問內存的十萬倍左右;

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

正是由於磁盤IO是非常昂貴的操作,所以計算機操作系統對此做了優化:預讀;每一次IO時,不僅僅把當前磁盤地址的數據加載到內存,同時也把相鄰數據也加載到內存緩沖區中。因為局部預讀原理說明:當訪問一個地址數據的時候,與其相鄰的數據很快也會被訪問到。每次磁盤IO讀取的數據我們稱之為一頁(page)。一頁的大小與操作系統有關,一般為4k或者8k。這也就意味着讀取一頁內數據的時候,實際上發生了一次磁盤IO。

2、B-Tree與二叉查找樹的對比

二叉查找樹查詢的時間復雜度是O(logN),查找速度最快和比較次數最少,既然性能已經如此優秀,但為什么實現索引是使用B-Tree而不是二叉查找樹,關鍵因素是磁盤IO的次數。

數據庫索引是存儲在磁盤上,當表中的數據量比較大時,索引的大小也跟着增長,達到幾個G甚至更多。當我們利用索引進行查詢的時候,不可能把索引全部加載到內存中,只能逐一加載每個磁盤頁,這里的磁盤頁就對應索引樹的節點。

下面先講講二叉樹


一、 二叉樹

先來看二叉樹查找時磁盤IO的次數:假設定義一個樹高為4的二叉樹,查找值為10:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第一次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第二次磁盤IO

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第三次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第四次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

從二叉樹的查找過程了來看,樹的高度和磁盤IO的次數都是4,所以最壞的情況下磁盤IO的次數由樹的高度來決定。

從前面分析情況來看,減少磁盤IO的次數就必須要壓縮樹的高度,讓瘦高的樹盡量變成矮胖的樹,所以B-Tree就在這樣的背景下誕生了。


二、B-Tree

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

B-tree

m階B-Tree滿足以下條件:

1、每個節點最多擁有m個子樹

2、根節點至少有2個子樹

3、分支節點至少擁有m/2顆子樹(除根節點和葉子節點外都是分支節點)

4、所有葉子節點都在同一層、每個節點最多可以有m-1個key,並且以升序排列

如下有一個3階的B樹,觀察查找元素21的過程:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第一次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

第二次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

這里有一次內存比對:分別跟3與12比對

第三次磁盤IO:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

這里有一次內存比對,分別跟14與21比對

從查找過程中發現,B樹的比對次數和磁盤IO的次數與二叉樹相差不了多少,所以這樣看來並沒有什么優勢。

但是仔細一看會發現,比對是在內存中完成中,不涉及到磁盤IO,耗時可以忽略不計。另外B樹種一個節點中可以存放很多的key(個數由樹階決定)。

相同數量的key在B樹中生成的節點要遠遠少於二叉樹中的節點,相差的節點數量就等同於磁盤IO的次數。這樣到達一定數量后,性能的差異就顯現出來了。

 


三、B樹的新增

在剛才的基礎上新增元素4,它應該在3與9之間:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 


四、B樹的刪除

刪除元素9:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 


五、B+樹

完B樹,再來說說B+樹,B+樹和結構很類似,但查詢性能上更高,具有如下的特性:

  • 有k個子樹的中間節點包含有k個元素(B樹中是k-1個元素),每個元素不保存數據,只用來索引,所有數據都保存在葉子節點;
  • 葉子節點中包含了全部元素的信息,按照關鍵字的大小從左到右排序;
  • 中間節點的元素同時存在於子節點中,在子節點元素中是最大。

下面放張示例圖:

基於磁盤IO角度來看二叉樹、B-tree樹、B+樹

 

從圖中可以看出,B+樹中間節點和葉子節點有重復的數據,這里聲明一下,中間節點保存的只是子樹數據的子針,並不是真實的數據,所以中間節點的存儲占用空間較少。

同時,葉子節點之間用指針連在一起,換句話說,葉子節點形成了一個鏈表,把所有的數據都存儲了進來。

為什么這樣設計,比起B樹有什么好處呢?

首先,因為B+樹的中間節點只是保存子樹的最大數據和子樹的子針,本身的占用空間較小,因此可以容納更多節點元素,也就是說同樣數據情況下,B+ 樹會 B 樹更加“矮胖”,因此查詢效率更快。

其次,查找某個范圍的數據,只需在B+樹的葉子節點鏈表中遍歷即可,不需要像B 樹那樣挨個中序遍歷比較大小。總結來說,B+樹的優點就是:

  1. 層級更低,IO 次數更少;
  2. 每次都需要查詢到葉子節點;
  3. 查詢性能穩定葉子節點形成有序鏈表,范圍查詢方便

總結

插入或者刪除元素都會導致節點發生裂變反應,有時候會非常麻煩,但正因為如此才讓B樹能夠始終保持多路平衡,這也是B樹自身的一個優勢:自平衡;B樹主要應用於文件系統以及部分數據庫索引,如MongoDB,所以目前大部分關系型數據庫索引是使用B+樹實現。

B樹:有序數組+平衡多叉樹;

B+樹:有序數組鏈表+平衡多叉樹;


免責聲明!

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



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