B樹與B+樹不同的地方在於插入是從底向上進行(當然查找與二叉樹相同,都是從上往下)
二者都通常用於數據庫和操作系統的文件系統中,非關系型數據庫索引如mongoDB用的B樹,大部分關系型數據庫索引使用的是B+樹。
一、B樹(也叫B-樹,注意並不是讀B減樹哦)
m階B樹需滿足以下要求:
1、m階B樹:m階指的是分叉的個數最多為m個。即一個非葉子節點最多可以有m個子節點。
2、子節點:一個叉連接的表示一個子節點,如果所示CFJM 表示一個子節點,其中CFJM表示4個元素。一個非葉子節點可以表示為[A0 k1 A1 k2 A2……kn An],其中ceil(m/2) -1 <= k <= m-1個,因此ceil(m/2) <= A <= m,A表示指向子節點的指針。
3、根節點至少有兩個子節點。
4、所有的葉子在同一層。
上圖所示並未畫出葉子節點,因為葉子結點不包含元素,所以可以把葉子結點看成在樹里實際上並不存在外部結點,指向這些外部結點的指針為空,葉子結點的數目正好等於樹中所包含的元素總個數加1。下圖畫出了葉子節點。
B樹的特點可以總結為如下:
- 元素集合分布在整顆樹中。
- 任何一個元素出現且只出現在一個節點中。
- 搜索有可能在非葉子節點結束。
- 因為每個節點中的元素和子樹都是有序的,其搜索性能等價於在元素集合內做一次二分查找。
- B樹在插入刪除新的數據記錄會破壞B-Tree的性質,因為在插入刪除時,需要對樹進行一個分裂、合並、轉移等操作以保持B-Tree性質。
為什么要使用B-樹作為數據庫索引而不是使用二叉樹?
二叉樹的搜索效率是十分高的,可以達到logN,但是由於數據量巨大時,索引的大小甚至可以達到G級別,所以索引是存儲在磁盤中的,每次查找只能逐一將索引樹的節點加載至內存中,如果使用二叉樹則I/O操作將會非常頻繁,I/O次數取決於二叉樹的深度。這樣索引速度非常慢,因此采用B樹這種多路二叉搜索樹大大減少I/O次數。其中多路指的是一個節點有多個子樹,並且由於所有葉子節點都在同一層,因此是平衡樹。
磁盤頁:查詢索引時,逐一加載磁盤頁,這里的磁盤頁對應索引樹的節點,對於m階B樹,m的大小取決於磁盤頁的大小。
B+樹
m階B樹具有以下幾個特征:
1、有k個子樹的中間節點包含有k個元素(B樹中是k-1個),每個元素不保存數據,只用來索引,所有數據都保存在葉子節點中。
2、所有的葉子結點中包含了全部元素的信息,葉子節點本身根據元素的大小順序鏈接。
3、所有的中間節點元素都同時存在子節點,在子節點元素中是最大(或最小)元素。
對於根節點中的8,在其子節點中 2 5 8中是最大元素,根節點的最大元素15也是整棵樹的最大元素。
什么是衛星數據?
索引元素所指向的數據記錄,比如數據庫中的某一行。
在B樹中無論是中間節點還是葉子節點都帶有衛星數據,但是在B+樹中只有葉子節點帶有衛星數據,中間節點僅僅是索引。左圖是B樹,右圖是B+樹。
相比B樹B+樹有以下幾點優點:
(1)由於B+樹的中間節點沒有衛星數據,因此同樣大小的磁盤頁可以容納更多的節點元素,即B+樹相比B樹更加矮胖,因此查詢時的I/O次數更少。
(2)由於B樹在查找時最好情況是根節點,最差情況是葉子節點;B+樹都是查找到葉子節點,所以B+樹的查找更加穩定。
(3)對於范圍查找,例如查找3-11之間的所有數據,對於B樹,查找下限3,然后中序遍歷;對於B+樹只需要在葉節點鏈表上遍歷即可,范圍查找的效率更高。
數據庫中的聚集索引中,葉子節點直接包含衛星數據,在非聚集索引中,葉子節點帶有指向衛星數據的指針。