天天看點

關于B樹和B+樹

背景

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

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

最常用的資料盡可能放在更高層、更小的存儲器中,隻有在目前層找不到,才向更低層、更大的存儲器中尋找。這也就解釋了,當處理大規模資料的時候(指無法将資料一次性存入記憶體),算法的實際運作時間,往往取決于資料在不同存儲級别之間的IO次數。是以,要想提升速度,關鍵在于減少IO。

磁盤讀取資料是以資料塊(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+樹

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+樹單次磁盤IO的資訊量大于B樹,I/O的次數相對減少。
  • MySQL是一種關系型資料庫,區間通路是常見的一種情況,B+樹葉結點增加的鍊指針,加強了區間通路性,可使用在區間查詢的場景;而使用B樹則無法進行區間查找。