B+樹索引


B+樹索引文件

B+s樹采用平衡樹的結構,根到葉的每條路徑長度相同,每個非葉結點有
\(\left \lceil n/2 \right \rceil\) ~ \(n\)個指針

如圖,對於一個包含m個指針的結點(\(m \leq n\))有\(K_{i-1} \leq val(P_i) < K_i\) ( i = 2,3,...,m-1), \(P_1\)指向小於\(K_1\)的部分, \(P_m\)指向大於等於\(K_{m-1}\)的部分,通常將一個結點的指針數稱為扇出(fanout)

B+樹查詢


如果沒有重復的搜索碼,我們找到最小的i使得\(K_i\)大於等於V,如果\(K_i == V\),則將當前結點設置為\(P_{i+1}\), 如果\(K_i > V\),則將當前結點設置為\(P_i\),如果葉結點中沒有等於V的搜索碼值,則find返回空值表示失敗。
如果有重復的搜索碼,則\(i < j\), \(K _i < K_j\)不一定成立,但一定有\(K _i \leq K_j\),也就是相同搜索碼可能在一些連續的結點中,於是我們修改Find方法,即使\(V == K_i\),也將其置為\(P_i\),在到達葉結點的時候,找到第一個符合條件的值,這樣我們將find方法修改為findFirst,然后在葉結點遍歷,范圍查詢(range query)也是如此,查找(L, U)是先findFirst(L),只是結束條件變成了\(K_i\)> U而不是V

如果文件有N個搜索碼值,那么這條路徑的長度不會超過\(\left \lceil log_{\left \lceil n/2 \right \rceil} (N))\right \rceil\),結點大小一般等於磁盤大小4KB,如果搜索碼大小為12字節,磁盤指針大小為8字節,那么n大約為200,更保守估計,搜索碼大小達到32字節,n也大約為100。n=100,文件中搜索碼值有100萬時,一次查找也只需要訪問\(\left \lceil log_{\left \lceil 50 \right \rceil} (1 000 000))\right \rceil\) = 4個結點,通常根結點訪問頻繁,很可能在緩沖區中,因此一般只需要從磁盤讀三個或更少的磁盤塊

B+樹與內存中的二叉樹的區別

B+樹與二叉樹的一個重大區別在於結點的大小和樹的高度,B+樹一般矮而胖,二叉樹一般瘦而高

B+樹的更新

插入

若葉結點未滿,則直接插入
當葉結點過滿,則需要分裂葉結點,將新結點的最小搜索碼值插入其父結點中,這樣也可能會引起父結點過滿,則遞歸向上處理,直到不再產生分裂或生成新的根結點為止


刪除

若刪除導致結點太空,這種情況下,我們考慮其兄弟結點,如果能合並就合並,如果合並超過了最大數量n,則需要在該結點和其兄弟結點間重新分配指針,以便每個結點至少含\(\left \lceil n/2 \right \rceil\)個指針,如下圖,將左邊兄弟結點的最右指針移動到太空的右邊兄弟



B+樹擴展

輔助索引

B+樹可能改變記錄的位置,但記錄本身並沒有更新,如結點分裂,這樣所有存儲了重定位的輔助索引必須更新,其代價可能十分高昂,為解決這個問題,在輔助索引中,不存儲指向被索引記錄的指針,而是存儲主索引搜索碼的值,然后通過主索引來找到對應的記錄

字符串上的索引

在字符串上創建索引會引來兩個問題,

  • 字符串是變長的
  • 字符串可能會很長,導致結點扇出降低以及增加樹的高度

對於變長搜索碼,即使結點全滿,不同的節點也會有不同的扇出,如果一個結點已滿,則它必須分裂,所以結點的分裂取決於結點的空間使用比例,而不是結點的最大可容量項數
使用前綴壓縮可以增加結點的扇出,如對於由搜索碼“Silberschatz”分開的兩個子樹中最相近的碼值為“Silas”與“Silver”,則非葉結點存儲“Slib”就夠了而不用存儲“Silberschatz”

多碼訪問

使用多個單碼索引


對於上述查詢語句,有三種查詢策略

  • 利用dept_name上的索引,找出所有屬於“Finance”的記錄,然后逐一檢查是否滿足salary=80000
  • 利用salary上的索引,找出所有salary=80000的記錄,然后逐一檢查是否滿足屬於“Finance”
  • 利用dept_name上的索引找到滿足dept_name=“Finance”的所有指針,利用salary上的索引,找出所有salary=80000的所有指針,取交集

最后一種方案利用了已存在的多個索引的優勢,但是如果下列條件都成立,這種策略也可能是種糟糕的選擇

  • dept_name=“Finance”的記錄太多
  • salary=80000的記錄太多
  • dept_name=“Finance”且salary=80000的只有幾個
    如果上述條件成立,則為了得到一個很小的結果集,我們必須掃描大量指針

多碼索引

也可以在復合搜索碼(dept_name, salary)上建立和使用索引
可以很簡單處理

但對於下列這種范圍查詢,由於每條記錄可能位於不同的磁盤塊,將導致大量的IO操作

覆蓋索引

覆蓋索引存儲一些其他屬性的值和指向記錄的指針,假如建立在instructor關系的ID屬性上的非聚集索引,如果存儲額外的salary屬性,則查詢salary時,不需要訪問及記錄,雖然在搜索碼(ID,salary)上建立索引能達到同樣的效果,但是覆蓋索引能夠減小搜索碼的大小,使得非葉結點有更大的扇出

位圖索引

位圖就是位的簡單數組
使用位圖索引能夠加快“使用多個單碼索引”中第三種策略的集合交操作

參考


免責聲明!

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



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