動態查詢樹主要有:二叉查詢樹(binary search tree),平衡二叉查詢樹(balanced binary search tree),紅黑樹(red-black tree ),b-tree/b+-tree/ b*-tree (b~tree)。前三者是典型的二叉查詢樹結構,其查詢的時間複雜度o(log2n)與樹的深度相關,那麼降低樹的深度自然會提高查詢效率。
但是咱們有面對這樣乙個實際問題:就是大規模資料儲存中,實現索引查詢這樣乙個實際背景下,樹節點儲存的元素數量是有限的(如果元素數量非常多的話,查詢就退化成節點內部的線性查詢了),這樣導致二叉查詢樹結構由於樹的深度過大而造成磁碟i/o讀寫過於頻繁,進而導致查詢效率低下,那麼如何減少樹的深度,乙個基本的想法就是:採用多叉樹結構。
這樣我們就提出了乙個新的查詢樹結構——多路查詢樹。根據平衡二叉樹的啟發,自然就想到平衡多路查詢樹結構,也就是這篇文章所要闡述的第乙個主題b~tree,即b樹結構(後面,我們將看到,b樹的各種操作能使b樹保持較低的高度,從而達到有效避免磁碟過於頻繁的查詢訪問操作,從而有效提高查詢效率)。
索引是資料庫為了提高查詢效率提供的一種冗餘結構,保守計算資料庫50%以上的調優可以通過調整索引來進行優化。b+樹索引是我們日常工作最常用的索引,大家平時在工作中說的」索引」預設都是b+樹索引。
b樹:即(所謂的b-樹)搜尋有可能在非葉子結點結束。
b+樹:所有關鍵字都在葉子結點出現。
b+樹索引是基於二叉樹結構的。b+樹索引結構有3個基本組成部分:根節點、分支節點和葉子節點。其中根節點位於索引結構的最頂端,而葉子節點位於索引結構的最底端,中間為分子節點。
可以用下圖來描述b樹索引的結構。其中,b表示分支節點,而l表示葉子節點。
1、 其所包含的索引條目都是按照順序排列的(預設是公升序排列,也可以在建立索引時指定為降序排列)。
2、 每個索引條目(也可以叫做每條記錄)都具有兩個字段。第乙個字段表示當前該分支節點塊下面所鏈結的索引塊中所包含的最小鍵值;第二個欄位為四個位元組,表示所鏈結的索引塊的位址,該位址指向下面乙個索引塊。
3、 在乙個分支節點塊中所能容納的記錄行數由資料塊大小以及索引鍵值的長度決定。比如從上圖可以看到,對於根節點塊來說,包含三條記錄,分別為(0 b1)、(500 b2)、(1005 b3)
,它們指向三個分支節點塊。其中的0、500和1005分別表示這三個分支節點塊所鏈結的鍵值的最小值。而b1、b2和b3則表示所指向的三個分支節點塊的位址。
1、 b+樹索引的所有葉子塊一定位於同一層上,這是由b樹的資料結構定義的。oracle 設計的b+樹索引結構保證了b+樹索引從根到葉子都有相等的分支節點,保證了b+樹索引的平衡,這樣就不會因為基表的資料插入和刪除操作造成b樹索引變得不平衡,從而影響索引的效能。
因此,從根塊到達任何乙個葉子塊的遍歷代價都是相同的; 索引高度是指從根塊到達葉子塊時所遍歷的資料塊的個數,通常,大多數的b+樹索引的高度都是2到3,也就意味著,即使表中有上百萬條記錄,從索引中定位乙個鍵字只需要2或3次i/o,索引越高,效能越差;
2、 葉子節點所包含的索引條目與分支節點一樣,都是按照順序排列的(預設是公升序排列,也可以在建立索引時指定為降序排列)
3、 每個索引條目(也可以叫做每條記錄)也具有兩個字段。第乙個字段表示索引的鍵值,對於單列索引來說是乙個值;而對於多列索引來說則是多個值組合在一起的。第二個字段表示鍵值所對應的記錄行的rowid,該rowid是記錄行在表裡的實體地址。rowid 是唯一的oracle 指標,指向該行的物理位置,使用rowid 是oracle 資料庫中訪問行最快的方法。
4、 葉子節點其實是乙個雙向鍊錶,每個葉子節點包含乙個指向下乙個和上乙個葉子點的指標,這樣可以方便地在一定範圍內遍歷索引。
b樹索引雖然是乙個樹狀的立體結構,但其對應到資料檔案裡的排列當然還是乙個平面的形式,也就是像下面這樣。
/根/分支/分支/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/葉子/葉子/…/葉子/分支/…..因此,當oracle需要訪問某個索引塊的時候,勢必會在這個結構上跳躍移動。
當oracle需要獲得乙個索引塊時,首先從根節點開始,根據所要查詢的鍵值,從而知道其所在的下一層的分支節點,然後訪問下一層的分支節點,再次同樣根據鍵值訪問再下一層的分支節點,如此這般,最終訪問到最底層的葉子節點。
可以看出,其獲得物理i/o塊時,是乙個接著乙個,按照順序序列進行的。在獲得最終物理塊的過程中,我們不能同時讀取多個塊,因為我們在沒有獲得當前塊的時候是不知道接下來應該訪問哪個塊的。因此,在索引上訪問資料塊時,我們是按照順序從乙個索引塊跳到另乙個索引塊,從而找到最終的索引塊的。
那麼對於全表掃瞄來說,則不存在訪問下乙個塊之前需要先訪問上乙個塊的情況。全表掃瞄時,oracle知道要訪問所有的資料塊,因此唯一的問題就是盡可能高效地訪問這些資料塊。因此,這時oracle可以採用同步的方式,分幾批,同時獲取多個資料塊。這幾批的資料塊在物理上可能是分散在表裡的。
b樹的非葉子節點也儲存指向最終元素的指標;而b+樹只有在葉子節點才能找到指向最終元素的指標。
為什麼說b+-tree比b 樹更適合實際應用中作業系統的檔案索引和資料庫索引?
b+-tree的磁碟讀寫代價更低
b+-tree的內部結點並沒有指向關鍵字具體資訊的指標。因此其內部結點相對b 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說io讀寫次數也就降低了。
b+-tree的查詢效率更加穩定
由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每乙個資料的查詢效率相當。
b+樹只要遍歷葉子節點就可以實現整棵樹的遍歷。而且在資料庫中基於範圍的查詢是非常頻繁的,而b樹不支援這樣的操作(或者說效率太低)。
r樹在資料庫等領域做出的功績是非常顯著的。它很好的解決了在高維空間搜尋等問題。舉個r樹在現實領域中能夠解決的例子吧:查詢20英里以內所有的餐廳。如果沒有r樹你會怎麼解決?一般情況下我們會把餐廳的座標(x,y)分為兩個字段存放在資料庫中,乙個字段記錄經度,另乙個字段記錄緯度。這樣的話我們就需要遍歷所有的餐廳獲取其位置資訊,然後計算是否滿足要求。如果乙個地區有100家餐廳的話,我們就要進行100次位置計算操作了,如果應用到谷歌地圖這種超大資料庫中,我想這種方法肯定不可行吧。
r樹就很好的解決了這種高維空間搜尋問題。它把b樹的思想很好的擴充套件到了多維空間,採用了b樹分割空間的思想,並在新增、刪除操作時採用合併、分解結點的方法,保證樹的平衡性。因此,r樹就是一棵用來儲存高維資料的平衡樹。
可以把r樹看作是b+樹在高維空間上的拓展。
具體可見r樹
B樹B 樹B 樹和B 樹
原文link b樹 即二叉搜尋樹 1.所有非葉子結點至多擁有兩個兒子 left和right 2.所有結點儲存乙個關鍵字 3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹 如 b樹的搜尋,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那麼就命中 否則,如果查詢關鍵字比結點...
B 樹 B 樹 B 樹和B 樹
b樹 即二叉搜尋樹 1.所有非葉子結點至多擁有兩個兒子 left 和right 2.所有結點儲存乙個關鍵字 3.非葉子結點的左指標指向小於其關鍵字的子樹,右指標指向大於其關鍵字的子樹 如 b樹的搜尋,從根結點開始,如果查詢的關鍵字與結點的關鍵字相等,那麼就命中 否則,如果查詢關鍵字比結點關鍵字小,就...
B樹 B 樹和B 樹
一 b樹的查詢是在內部節點進行的,節點處存放了節點的所有資訊,即相當於存放的是乙個node。二 b 樹的查詢最終會在外部節點,或者稱為葉子節點,而內部節點不存放node,只存放node的索引,最終能夠在葉子節點處找到乙個指向該node的指標,從而結束查詢。b 樹的另乙個特點是在葉子節點中存放的所有n...