你知道爲什麼要選擇B+樹作爲數據庫索引結構?談談你的理解

背景

首先,來談談B樹。爲什麼要使用B樹?我們需要明白以下兩個事實:

【事實1】

不同容量的存儲器,訪問速度差異懸殊。以磁盤和內存爲例,訪問磁盤的時間大概是ms級的,訪問內存的時間大概是ns級的。有個形象的比喻,若一次內存訪問需要1秒,則一次外存訪問需要1天。所以,現在的存儲系統,都是分級組織的。

最常用的數據儘可能放在更高層、更小的存儲器中,只有在當前層找不到,才向更低層、更大的存儲器中尋找。這也就解釋了,當處理大規模數據的時候(指無法將數據一次性存入內存),算法的實際運行時間,往往取決於數據在不同存儲級別之間的IO次數。因此,要想提升速度,關鍵在於減少IO。

【事實2】

磁盤讀取數據是以數據塊(block)(或者:頁,page)爲基本單位的,位於同一數據塊中的所有數據都能被一次性全部讀取出來。

換句話說,從磁盤中讀1B,與讀1KB幾乎一樣快!因此,想要提升速度,應該利用外存批量訪問的特點,在一些文章中,也稱其爲磁盤預讀。系統之所以這麼設計,是基於一個著名的局部性原理:

當一個數據被用到時,其附近的數據也通常會馬上被使用,程序運行期間所需要的數據通常比較集中

B樹

假設有10億條記錄(100010001000),如果使用平衡二叉搜索樹(Balanced Binary Search Tree, BBST),最壞的情況下,查找需要log(2, 10^9) = 30次 I/O 操作,且每次只能讀出一個關鍵字(即如果這次讀出來的關鍵字不是我要查找的,就要再進行一次I/O去讀取數據)。如果換成B樹,會是怎樣的情況呢?

B 樹是爲了磁盤或其它輔助存儲設備而設計的一種多叉平衡搜索樹。多級存儲系統中使用B樹,可針對外部查找,大大減少I/O次數。通過B樹,可充分利用外存對批量訪問的高效支持,將此特點轉化爲優點。每下降一層,都以超級結點爲單位(超級結點就是指一個結點內包含多個關鍵字),從磁盤中讀入一組關鍵字。那麼,具體多大爲一組呢?

一個節點存放多少數據視磁盤的數據塊大小而定,比如磁盤中1 block的大小有1024KB,假設每個關鍵字的大小爲 4 Byte,則可設定每一組的大小m = 1024 KB / 4 Byte = 256。目前,多數數據庫系統採用 m = 200~300。假設取m = 256,則B樹存儲1億條數據的樹的高度大概是 log(256, 10^9) = 4,也就是單次查詢所需要進行的I/O次數不超過 4 次,由此大大減少了I/O次數。

一般來說,B樹的根節點常駐於內存中,B樹的查找過程是這樣的:首先,由於一個節點內包含多個(比如,是256個)關鍵碼,所以需要先順序/二分來查找,如果找到則查找成功;如果失敗,則根據相應的引用從磁盤中讀入下一層的節點數據(這裏就涉及到一次磁盤I/O),同樣的在節點內順序查找,如此往復進行…事實上,B樹查找所消耗的時間很大一部分花在了I/O上,所以減少I/O次數是非常重要的。

B樹的定義

B樹就是平衡的多路搜索樹,所謂的m階B樹,即m路平衡搜索樹。根據維基百科的定義,一棵m階B樹需滿足以下要求:

  • 每個結點至多含有m個分支節點(m>=2)。

  • 除根結點之外的每個非葉結點,至少含有┌m/2┐個分支。

  • 若根結點不是葉子結點,則至少有2個孩子。

  • 一個含有k個孩子的非葉結點包含k-1個關鍵字。(每個結點內的關鍵字按升序排列)

  • 所有的葉子結點都出現在同一層。實際上這些結點並不存在,可以看作是外部結點。

根據節點的分支的上下限,也可以稱其爲(┌m/2┐, m)樹。比如,階數m=4時,這樣的B樹也可以稱爲(2,4)樹。(事實上,(2,4)樹是一棵比較特殊的B樹,它和紅黑樹有着特別的淵源!後面談及紅黑樹時會談到。)

並且,每個內部結點的關鍵字都作爲其子樹的分隔值。比如,某結點含有2個關鍵字(假設爲a1和a2),也就是說該結點含有3個子樹。那麼,最左子樹的關鍵字均小於a1;中間子樹的關鍵字介於a1~a2;最右子樹的關鍵字均大於a2。

示例,一棵3階的B樹是這個樣子:

B樹的高度(瞭解)

假定一棵B樹非空,具有n個關鍵字、高度爲h(令根結點爲第1層)、階數爲m,那麼該B樹的最大高度和最小高度分別是多少?

最大高度

當樹的高度最大時,則每個結點含有的關鍵字數應該儘量少。根據定義,根結點至少有2個孩子(即1個關鍵字),除根結點之外的非葉結點至少有┌m/2┐個孩子(即┌m/2┐-1個關鍵字),爲了描述方便,這裏令p = ┌m/2┐。

  • 第1層 1個結點 (含1個關鍵字)

  • 第2層 2個結點 (含2*(p-1)個關鍵字)

  • 第3層 2p個結點 (含2p*(p-1)^2個關鍵字)

  • 第h層 2p^(h-2)個結點

故總的結點個數n

≥ 1+(p-1)*[2+2p+2p^2+...+2p^(h-2)]
≥ 2p^(h-1)-1

從而推導出 h ≤ log_p[(n+1)/2] + 1 (其中p爲底數,p=┌m/2┐)

最小高度

當樹的高度最低時,則每個結點的關鍵字都至多含有m個孩子(即m-1個關鍵字),則有

n ≤ (m-1)*(1 + m + m^2 +...+ m^(h-1)) = m^h - 1

從而推導出 h ≥ log_m(n+1) (其中m爲底數)

B+樹

B+樹的定義

B+樹是B樹的一個變體,B+樹與B樹最大的區別在於:

  • 葉子結點包含全部關鍵字以及指向相應記錄的指針,而且葉結點中的關鍵字按大小順序排列,相鄰葉結點用指針連接。

  • 非葉結點僅存儲其子樹的最大(或最小)關鍵字,可以看成是索引。

一棵3階的B+樹示例:(好好體會和B樹的區別,兩者的關鍵字是一樣的)

問:爲什麼說B+樹比B樹更適合實際應用中操作系統的文件索引和數據庫索引?

答:

  • B+樹更適合外部存儲。由於內結點不存放真正的數據(只是存放其子樹的最大或最小的關鍵字,作爲索引),一個結點可以存儲更多的關鍵字,每個結點能索引的範圍更大更精確,也意味着B+樹單次磁盤IO的信息量大於B樹,I/O的次數相對減少。

  • MySQL是一種關係型數據庫,區間訪問是常見的一種情況,B+樹葉結點增加的鏈指針,加強了區間訪問性,可使用在區間查詢的場景;而使用B樹則無法進行區間查找。

寫在最後

歡迎大家關注我的公衆號【風平浪靜如碼】,海量Java相關文章,學習資料都會在裏面更新,整理的資料也會放在裏面。

覺得寫的還不錯的就點個贊,加個關注唄!點關注,不迷路,持續更新!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章