前面談了 B+樹的基本概念,今日主要說一下 B+樹的查找操作。
下面所有的查找操作都是在上面這顆 B+樹上進行了,爲此,我們先仔細觀察一下這顆B+樹(毫不隱瞞,這顆 B+樹出自於嚴蔚敏老師的數據結構教材)。
第一點:B+樹中的所有數據均保存在葉子結點,且根結點和內部結點均只是充當控制查找記錄的媒介,並不代表數據本身,所有的內部結點元素都同時存在於子結點中,是子節點元素中是最大(或最小)元素。
比如 B+ 樹中的結點 59
(結點 15、44、97、72
類似),是其子結點 [15、44、59]
中的最大元素,也是葉子結點 [51、59]
中的最大元素。所有的數據 [10、15、21、37、44、51、59、63、72、85、91、97]
均保存在葉子結點之中,而根結點 [59、97]
及內部結點 [15、44、59]
與 [72、97]
均不是數據本身,只是充當控制查找記錄的媒介。
需要注意的是,根結點的最大元素 97
是整顆 B+樹當中最大的元素,無論之後在葉子結點中插入或刪除多少元素,始終要保證最大元素在根結點當中,這個講插入和刪除時還會看到。
第二點:每一個葉子結點都有指向下一個葉子結點的 指針,便捷之處就在於之後我們將看到的區間查找。
查詢單個元素
我們以查詢 59
爲例進行說明。
第一次磁盤 I/O :訪問根結點 [59、97]
,發現 59
小於等於 [59、97]
中的 59
,則訪問根結點的第一個孩子結點。
第二次磁盤 I/O : 訪問結點 [15、44、59]
,發現 59
大於 44
且小於等於 59
,則訪問當前結點的第三個孩子結點 [51、59]
.
第三次磁盤 I/O :訪問葉子結點 [51、59]
,順序遍歷結點內部,找到要查找的元素 59
.
我想你已經注意到了和 B-樹的區別,對於 B+樹中單個元素的查找而言,每一個元素都有相同的磁盤 I/O操作次數,即使查詢的元素出現在根結點中,但那只是一個充當控制查找記錄的媒介,並不是數據本身,數據真正存在於葉子結點當中,所以 B+樹中查找任何一個元素都要從根結點一直走到葉子結點纔可以。
B+樹的非葉子結點均不存儲 Data
(即 ,官方將其稱爲衛星數據) ,所以與 B-樹相比,同樣大小的磁盤頁,B+樹的非葉子結點可以存儲更多的索引(關鍵字),這也就意味着在數據量相同的情況下,B+樹的結構比 B-樹更加 “矮胖”,查詢時磁盤 I/O 次數會更少。
注意: B-樹的查詢性能並不穩定,對於根結點中關鍵字可能只有一次磁盤 I/O,而對於葉子結點中的關鍵字需要樹的高度次磁盤 I/O 操作。
比如查找上圖 B-樹中的關鍵字 59
僅需要一次磁盤 I/O 操作,關鍵字 21
需要 3 次磁盤 I/O,關鍵字 72
需要 2 次磁盤 I/O.
B+樹所有查詢所有關鍵字的磁盤 I/O 的次數都是樹的高度。
區間查詢
爲了更清楚地看到 B+樹進行區間查詢的優勢,我們以查詢下面的 B-樹中大於等於21 ,小於等於63的關鍵字爲例進行說明。
第一步:訪問 B-樹的根結點 [59]
,發現 21
比 59
小,則訪問根結點的第一個孩子 [15、44]
.
第二步:訪問結點 [15、44]
,發現 21
大於 15
且小於 44
,則訪問當前結點的第二個孩子結點 [21、37]
。
第三步:訪問結點 [21、37]
, 找到區間的左端點 21
,然後從該關鍵字 21
開始,進行中序遍歷,依次爲關鍵字 37 、44、51、59
,直到遍歷到區間的右端點 63
爲止, 不考慮中序遍歷過程的壓棧和入棧操作,磁盤 I/O 次數多了 2次,即訪問結點 72
和結點 63
並加載進內存。
而 B+樹進行區間查找,簡直要舒服的不要不要的。同樣是查找區間 [21,63]
之間的關鍵字。
第一步:訪問根結點 [59、97]
, 發現區間的左端點 21
小於 59
, 則訪問第一個孩子結點 [15、44、59]
.
第二步:訪問結點 [15、44、59]
,發現 21
大於 15
且小於 44
,則訪問第二個孩子結點 [21、37,44]
.
第三步:訪問結點 [21、37,44]
,找到了左端點 21
,此時 B+樹的優越性就出來了,不再需要中序遍歷,而是相當於單鏈表的遍歷,直接從左端點 21
開始一直遍歷到左端點 63
即可,沒有任何額外的磁盤 I/O 操作。
綜合來看 B+樹的優勢就是:
查找時磁盤 I/O 次數更少,因爲 B+樹的非葉子結點可以存儲更多的關鍵字,數據量相同的情況下,B+樹更加 “矮胖” ,效率更高。
B+樹查詢所有關鍵字的磁盤 I/O 次數都一樣,查詢效率穩定。
B+樹進行區間查找時更加簡便實用。
此外給大家推薦一篇博文 MySQL索引背後的數據結構及算法原理(http://blog.codinglabs.org/articles/theory-of-mysql-index.html) ,其中對於MySQL 索引爲什麼採用 B+樹,以及InnoDB表爲什麼必須有主鍵,並且爲什麼推薦使用自增主鍵都有解釋,需要的朋友可以自提,我就不再造輪子了。
推薦閱讀:
作者:景禹,一個追求極致的共享主義者,想帶你一起擁有更美好的生活,化作你的一把傘。