<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          正確理解 B+樹(shù)

          共 5155字,需瀏覽 11分鐘

           ·

          2021-04-06 11:34

          B+樹(shù)是為磁盤和存儲(chǔ)工具設(shè)計(jì)的一種數(shù)據(jù)結(jié)構(gòu),它是一種平衡查找樹(shù),它在查找,插入、修改方面的時(shí)間復(fù)雜度都穩(wěn)定為 O(logn)

          節(jié)點(diǎn)

          圖(1)


          B+樹(shù)節(jié)點(diǎn)是一組按照key有序的元素,B+樹(shù)包含兩種類型的節(jié)點(diǎn),一種是索引節(jié)點(diǎn),一種是葉子節(jié)點(diǎn)

          • 索引節(jié)點(diǎn)也叫內(nèi)部節(jié)點(diǎn),索引節(jié)點(diǎn)只包含key,不包含data, 節(jié)點(diǎn)的 key是升序排列的,對(duì)于指定的索引節(jié)點(diǎn)key來(lái)說(shuō),它左子樹(shù)上所有的key都小于它的key,它右子樹(shù)上所有的key都大于等于它的key

          • 葉節(jié)點(diǎn)上存儲(chǔ)的是主鍵和數(shù)據(jù)(key和data), 所有的葉節(jié)點(diǎn)都在同一高度上,節(jié)點(diǎn)按key 從小到大并且通過(guò)指針使得彼此鏈接,這樣,所有的葉節(jié)點(diǎn)組成了一個(gè)雙向有序鏈表,葉節(jié)點(diǎn)這樣做的好處是在不訪問(wèn)索引的情況下能順序檢索數(shù)據(jù),也能很好的支持范圍查詢的快處理

          B+樹(shù)特點(diǎn)

          • 階數(shù)為 m 的B+樹(shù),每個(gè)索引節(jié)點(diǎn)最多有 m 個(gè)子節(jié)點(diǎn),每個(gè)索引節(jié)點(diǎn)頁(yè)面最多存儲(chǔ) m - 1 個(gè)索引key

          • 所有索引節(jié)點(diǎn)的子節(jié)點(diǎn)數(shù)在 Math.ceil(m / 2) 和 m 之間

          • B +樹(shù)之所以稱為平衡樹(shù),是因?yàn)閺母?jié)點(diǎn)到葉節(jié)點(diǎn)的每條路徑都具有相同的長(zhǎng)度。平衡樹(shù)意味著所有對(duì)單個(gè)值的搜索都需要從磁盤讀取相同數(shù)量的頁(yè)面。

          填充因子

          B+樹(shù)使用填充因子來(lái)控制頁(yè)面的分裂和合并,設(shè)置數(shù)據(jù)占用頁(yè)面空間的百分比,目的是為后面的數(shù)據(jù)預(yù)留一部分頁(yè)空間,當(dāng)有新數(shù)據(jù)時(shí),可以放到預(yù)留的頁(yè)空間中,避免分頁(yè)的發(fā)生

          默認(rèn)的填充因子是50%,對(duì)于一棵m階的B+樹(shù),填充因子是 m/2

          B+樹(shù)操作

          B+樹(shù)常用操作涉及到查詢、插入、刪除、范圍查詢, 為了便于說(shuō)明,下面所有操作的例子中的B+樹(shù)無(wú)特殊說(shuō)明都是5階樹(shù)

          每個(gè)頁(yè)面最多有4個(gè)key,大于等于5個(gè)時(shí)就需要分裂或者旋轉(zhuǎn)合并

          填充因子默認(rèn)是50%,頁(yè)面中已經(jīng)使用了的數(shù)量為2表示填充因子為50%,同理,小于2時(shí)候表示填充因子小于50%,大于2時(shí)候表示填充因子大于50%

          • 查詢

          B+樹(shù)的索引節(jié)點(diǎn)是有序的,查詢單個(gè)key的話直接用二分查找定位到目標(biāo)葉子頁(yè)面,在目標(biāo)葉子頁(yè)面中順序遍歷,找到目標(biāo)key,則返回葉子頁(yè)面中目標(biāo)key對(duì)應(yīng)的數(shù)據(jù)

          • 插入

          B+樹(shù)的插入操作完成以后,有以下幾種情況

          1. 葉節(jié)點(diǎn)和索引節(jié)點(diǎn)沒(méi)有滿

          這種情況插入操作步驟最少,根據(jù)key把數(shù)據(jù)插入到葉節(jié)點(diǎn)已經(jīng)排序的位置上即可,下圖中是插入key為 23的數(shù)據(jù),23會(huì)插入到包含 15, 21 的葉子頁(yè)面中,插入之后葉子頁(yè)面沒(méi)有滿,不用處理頁(yè)面分裂的情況

          2. 葉節(jié)點(diǎn)滿了,索引節(jié)點(diǎn)未滿
          步驟:
          (1):葉子頁(yè)面分裂成兩個(gè)頁(yè)面
          (2): 把中間行數(shù)據(jù)的key按順序加入到上一層的索引頁(yè)中
          (3): 所有小于中間行數(shù)據(jù)key的數(shù)據(jù)放到左葉子頁(yè)面
          (4): 所有大于等于中間行數(shù)據(jù)key的數(shù)據(jù)放到右葉子葉面

          圖(2)


          往圖(2) 的B+樹(shù)中插入key為28的數(shù)據(jù),這條數(shù)據(jù)會(huì)插入到包含15,21,23,27的葉子頁(yè)面中,插入之后,該頁(yè)面數(shù)據(jù)已滿,必須要分裂成如下所示的兩個(gè)頁(yè)面:

          左葉子頁(yè)面右葉子頁(yè)面
          15,2123,27,28

          中間行數(shù)據(jù)key為:23,放到上一層的索引頁(yè)面中15的后面,下面圖(3)是插入key為28的結(jié)果

          圖(3)


          3. 葉子頁(yè)面和索引頁(yè)面都滿了
          步驟:
          (1):葉節(jié)點(diǎn)頁(yè)面分裂成左右兩個(gè)葉子頁(yè)面
          (2): 把中間行數(shù)據(jù)的key按順序加入到索引頁(yè)中
          (3): 所有小于中間行數(shù)據(jù)key的數(shù)據(jù)放到左葉子頁(yè)面
          (4): 所有大于等于中間行數(shù)據(jù)key的數(shù)據(jù)放到右葉子頁(yè)面

          (5): 上面步驟(2)執(zhí)行之后,索引頁(yè)面滿了,分裂成左右兩個(gè)索引頁(yè)
          (6): 所有小于索引頁(yè)中間的key的放到左邊索引頁(yè)
          (7): 所有大于索引頁(yè)中間的key的放到右邊索引頁(yè)
          (8): 把索引頁(yè)中間的key放到更高一層的索引頁(yè)

          如果步驟(8)執(zhí)行之后,更高一層的索引頁(yè)滿了,繼續(xù)執(zhí)行(5)-(8)步驟

          圖(4)


          圖(4) 的B+樹(shù)插入key為30的數(shù)據(jù),這條數(shù)據(jù)會(huì)插入到 23, 27, 28, 29 的葉子頁(yè)面中,插入之后,該頁(yè)面數(shù)據(jù)已滿,必須要分裂成如下所示的兩個(gè)頁(yè)面:

          左葉子頁(yè)面右葉子頁(yè)面
          23,2728,29,30

          中間行數(shù)據(jù)key為:28,放到索引頁(yè)面中23 的后面

          28 放到索引頁(yè)面23的后面之后,索引頁(yè)變成了4, 7, 15, 23, 28, 這時(shí)索引頁(yè)也滿了,分裂成如下所示的三個(gè)頁(yè)面 :

          左索引頁(yè)右索引頁(yè)更高一層索引頁(yè)
          4,723,2815

          下面圖(5)為插入key為30數(shù)據(jù)之后,葉子頁(yè)面和索引頁(yè)面分裂之后的結(jié)果:

          圖(5)


          • 旋轉(zhuǎn)

          B+樹(shù)的插入操作會(huì)有頁(yè)面分裂的情況,頁(yè)面分裂就會(huì)有產(chǎn)生磁盤IO,相對(duì)內(nèi)存,磁盤 IO 要慢得多,所以為了減少磁盤IO操作,就要盡可能的減少頁(yè)面分裂,充分利用頁(yè)面空間,因此B+樹(shù)提供了旋轉(zhuǎn)操作

          旋轉(zhuǎn)操作的應(yīng)用場(chǎng)景: B+樹(shù)葉子頁(yè)面空間已經(jīng)滿了,但是它的左右兄弟頁(yè)面沒(méi)有滿

          葉子頁(yè)面空間滿了,B+樹(shù)會(huì)優(yōu)先檢查左右兄弟葉子頁(yè)面是否能容納數(shù)據(jù),當(dāng)左右兄弟頁(yè)面空間都滿了時(shí),才會(huì)考慮頁(yè)面分裂

          圖(6)


          圖(6)中,插入key為12的數(shù)據(jù),葉子頁(yè)面空間滿了,這時(shí)B+樹(shù)先檢查左兄弟頁(yè)面是否有多余的空間,通過(guò)旋轉(zhuǎn),把key分別為 7, 10, 11, 12, 13的葉子中的 7 移動(dòng)到左兄弟頁(yè)面中,移動(dòng)完成之后,左兄弟的key變成了 2, 5, 7

          同時(shí),葉子中key為7的數(shù)據(jù)在上層索引頁(yè)中也有記錄,所以需要把上層索引頁(yè)中key為7修改為 10,修改之后上層索引key分別為 10, 15,最終的結(jié)果如下圖(7)所示

          圖(7)


          葉子頁(yè)面插入新數(shù)據(jù)之后,頁(yè)面空間已滿,原本頁(yè)面是需要分裂的,但是通過(guò)把當(dāng)前頁(yè)面上的數(shù)據(jù)移動(dòng)到能容納數(shù)據(jù)的兄弟頁(yè)面中,減少了一次頁(yè)分裂,也即減少了一次磁盤IO操作

          • 刪除

          B+樹(shù)的刪除操作完成以后,有以下幾種情況

          1. 葉子頁(yè)面和索引頁(yè)面填充因子都大于等于50%

          這種情況直接刪除節(jié)點(diǎn),頁(yè)面會(huì)把刪除節(jié)點(diǎn)的位置標(biāo)記為空,以便存放后續(xù)其他的數(shù)據(jù),同時(shí),如果刪除的key出現(xiàn)在上層的索引頁(yè)面中,需要用葉子頁(yè)面中被刪除節(jié)點(diǎn)的下一個(gè)節(jié)點(diǎn)key去替換它

          圖(8)


          圖(8)中 7是待刪除的節(jié)點(diǎn),刪除7后,葉子頁(yè)面填充因子剛好等于50%,因?yàn)楸粍h除的7在上層的索引頁(yè)面中出現(xiàn)了相同的key,所以需要用葉子頁(yè)面中下一個(gè)key,也就是12替換上層索引頁(yè)面中的7,最終的結(jié)果如下面圖(9)所示:

          圖(9)


          2. 葉子頁(yè)面填充因子50%,索引頁(yè)面填充因子大于等于50%

          葉子頁(yè)面填充因子小于50%的時(shí)候,為了維持B+樹(shù)的平衡,會(huì)有頁(yè)面數(shù)據(jù)轉(zhuǎn)移和合并的操作

          從兄弟頁(yè)面轉(zhuǎn)移key數(shù)據(jù)到當(dāng)前頁(yè)面

          當(dāng)一個(gè)葉子頁(yè)面填充因子小于50%,左右兄弟頁(yè)面存在填充因子大于50%的時(shí)候,可以把兄弟頁(yè)面中的數(shù)據(jù)轉(zhuǎn)移到當(dāng)前頁(yè)面中,上一層索引頁(yè)面中因葉子頁(yè)面數(shù)據(jù)轉(zhuǎn)移受影響的索引key也需要做相應(yīng)的處理

          如果左右兄弟頁(yè)面的填充因子都大于50%時(shí),轉(zhuǎn)移任何一邊頁(yè)面數(shù)據(jù)到當(dāng)前頁(yè)面都可以,雖然選擇不同的頁(yè)面轉(zhuǎn)移數(shù)據(jù)后,B+樹(shù)的形態(tài)不一樣,但是最終都是滿足B+樹(shù)特點(diǎn)的

          圖(10)


          上面圖(10)中,刪除key為16的數(shù)據(jù) ( 圖中紅色標(biāo)識(shí)的區(qū)域 ),刪除之后,原來(lái)key為15, 16的葉子頁(yè)面變成了 15 ,頁(yè)面只剩下一個(gè)key

          此時(shí)頁(yè)面的填充因子小于50%,左兄弟頁(yè)面填充因子大于50%,滿足頁(yè)面數(shù)據(jù)轉(zhuǎn)移的條件

          把左兄弟頁(yè)面 (key為 7, 12, 13 )中的 13 轉(zhuǎn)移到當(dāng)前頁(yè)面中

          轉(zhuǎn)移之后,兩個(gè)頁(yè)面key數(shù)量剛好等于填充因子,左兄弟頁(yè)面key變?yōu)?nbsp;7, 12,當(dāng)前頁(yè)面的key變?yōu)?nbsp;13, 15

          當(dāng)前頁(yè)面中最小key值由原來(lái)的 15 變成了 13,為了保持B+數(shù)的平衡,需要把當(dāng)前頁(yè)面上一層的索引頁(yè)面中key為15替換為13, 最終的結(jié)果如下面圖(11)所示 :

          圖(11)


          當(dāng)前頁(yè)面key合并到兄弟頁(yè)面

          上面說(shuō)明了從兄弟頁(yè)面轉(zhuǎn)移數(shù)據(jù)到當(dāng)前頁(yè)面,現(xiàn)在我們來(lái)看下當(dāng)前頁(yè)面數(shù)據(jù)量小于填充因子的時(shí)候,如何合并到兄弟頁(yè)面中

          當(dāng)一個(gè)葉子頁(yè)面填充因子小于50%,左右兄弟頁(yè)面存在填充因子等于50%的時(shí)候,可以把這個(gè)葉子頁(yè)面合并到左右兄弟頁(yè)面中,上一層索引頁(yè)面中因葉子頁(yè)面數(shù)據(jù)合并受影響的索引key也需要做相應(yīng)的處理

          圖(12)


          在圖(12)中,執(zhí)行刪除key為15的操作(圖中紅色區(qū)域),15位于key為 13, 15 的頁(yè)面中,刪除15之后,當(dāng)前頁(yè)面key變成了 13, 只剩下一個(gè)key了

          此時(shí),當(dāng)前頁(yè)面填充因子小于50%,左右兄弟節(jié)點(diǎn)填充因子等于50%,所以無(wú)法從兄弟頁(yè)面轉(zhuǎn)移key數(shù)據(jù)到當(dāng)前頁(yè)面,但滿足當(dāng)前頁(yè)面數(shù)據(jù)合并到兄弟頁(yè)面的條件

          左右兄弟頁(yè)面都滿足當(dāng)前頁(yè)面數(shù)據(jù)合并過(guò)去,選擇任一兄弟頁(yè)面都可以,雖然選擇不同兄弟頁(yè)面,會(huì)導(dǎo)致B+樹(shù)的形態(tài)也不一樣,但最終都是讓B+樹(shù)維持平衡,這里我們選則合并到左兄弟頁(yè)面

          15 被刪除了之后,當(dāng)前頁(yè)面只剩下key為 13 的數(shù)據(jù)了

          它合并到左兄弟頁(yè)面之后, 當(dāng)前頁(yè)面為空,需要移除上一層索引頁(yè)面中指向當(dāng)前頁(yè)面的索引key 13, 移除13的索引key之后, 索引頁(yè)面key由原來(lái)的 7, 13, 23 變成 7, 23

          合并之后,左兄弟頁(yè)面key由原來(lái)的 7, 12 變成 7, 12, 13

          最終的結(jié)果如下面 圖(13) 所示 :

          圖(13)


          3. 葉子頁(yè)面和索引頁(yè)面填充因子都小于50%

          當(dāng)葉子頁(yè)面和索引頁(yè)面填充因子都小于50%的時(shí)候,葉子頁(yè)面和索引頁(yè)面都會(huì)有數(shù)據(jù)轉(zhuǎn)移或者合并的操作

          圖(14)


          在圖(14)中,執(zhí)行刪除葉子頁(yè)面中key為12的數(shù)據(jù)(圖中紅色區(qū)域),12 位于key為 7, 12 葉子頁(yè)面中,刪除 12 之后,當(dāng)前葉子頁(yè)面變成了 7,只剩下一個(gè)key了

          當(dāng)前葉子頁(yè)面左右兄弟頁(yè)面填充因子都是50%,所以滿足合并的條件,合并到左兄弟頁(yè)面或右兄弟頁(yè)面都可以,這里我們選擇合并到左兄弟頁(yè)面

          當(dāng)前葉子頁(yè)面中key為 7 的數(shù)據(jù)合并到左兄弟頁(yè)面之后,當(dāng)前葉子頁(yè)面沒(méi)數(shù)據(jù)了,而左兄弟頁(yè)面key變成了 2, 5, 7

          為了保持B+樹(shù)的平衡,指向當(dāng)前葉子頁(yè)面的上一層索引頁(yè)面中,需要?jiǎng)h除key為 7 的索引key, 刪除key為7的索引后,索引頁(yè)面key變成了 15, 這時(shí)該索引頁(yè)面填充因子小于50%,右兄弟頁(yè)面填充因子等于50%,滿足合并的條件

          但是,索引頁(yè)面數(shù)據(jù)合并到右兄弟頁(yè)面之后,根節(jié)點(diǎn)的左子樹(shù)就為空了,為了保持B+樹(shù)的平衡,根頁(yè)面數(shù)據(jù)需要合并到下一層的索引頁(yè)面中

          最后的結(jié)果如下面圖(15)所示 :

          圖(15)


          • 范圍查詢

          B+樹(shù)的葉子節(jié)點(diǎn)是按照key從小到大的順序組成的一個(gè)雙向鏈表,所以B+樹(shù)非常適合范圍查詢(這里說(shuō)的范圍是B+樹(shù)中索引節(jié)點(diǎn)的key的范圍)

          使用二分查找首先確定范圍查詢的起始key所在的葉子節(jié)點(diǎn)的位置,然后順序遍歷葉節(jié)點(diǎn)鏈表,直到葉節(jié)點(diǎn)key大于范圍查詢結(jié)束key,查詢停止

          B+樹(shù)的大小

          一顆 m 階的B+樹(shù),索引節(jié)點(diǎn)存儲(chǔ)的是索引信息,為了計(jì)算方便,這里假設(shè)一個(gè)索引key信息 8 字節(jié),一個(gè)磁盤頁(yè)面大概 4KB,那么一個(gè)磁盤頁(yè)面能容納的索引數(shù)量為:4 * 1024 / 8 = 512,此時(shí) m 就等于 512

          • 當(dāng)B+樹(shù)高度為2時(shí),最多能容納 512 (512的1次方) 個(gè)索引信息

          • 當(dāng)B+樹(shù)高度為3時(shí),最多能容納 26萬(wàn) (512的2次方)個(gè)索引信息

          • 當(dāng)B+樹(shù)高度為4時(shí),最多能容納 1.3億 (512的3次方)個(gè)索引信息

          • 當(dāng)B+樹(shù)高度為5時(shí),最多能容納 687億 (512的4次方)個(gè)索引信息

          從上面的數(shù)據(jù)可以看到,B+樹(shù)高度為5時(shí), 能容納 687 億個(gè)索引信息,可以非常夠用了

          在實(shí)際的應(yīng)用當(dāng)中,B+樹(shù)的根節(jié)點(diǎn)都是緩存在內(nèi)存中的,樹(shù)的最底層是葉子節(jié)點(diǎn)

          所以針對(duì)高度為5的B+樹(shù),查找一條指定key值的數(shù)據(jù)最多只需要3次磁盤IO就能定位到具體的葉子頁(yè)面,當(dāng)樹(shù)高度為4時(shí),最多只需要2次磁盤IO就能定位到具體的葉子頁(yè)面

          B+樹(shù)的應(yīng)用

          B+樹(shù)主要用于磁盤和存儲(chǔ)工具,著名的MySQL引擎 InnoDB 索引的數(shù)據(jù)模型使用的就是 B+ 樹(shù)

          當(dāng)數(shù)據(jù)超過(guò)一定的量級(jí)的時(shí)候,為了快速檢索數(shù)據(jù)而設(shè)置的索引信息也會(huì)變得非常龐大,而且這部分索引信息只能存儲(chǔ)在磁盤中,B+樹(shù)能從磁盤中快速檢索到需要的數(shù)據(jù),并且時(shí)間復(fù)雜度穩(wěn)定在O(logn)

          瀏覽 19
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  九九精品视频在线播放 | 69福利视频| 日本人日逼视频 | 苍井空在厨房被C的A片 | 男女日皮视频免费 |