面試官:你能說說數據庫索引爲什麼要採用B樹和B+樹嗎?

前面幾篇關於數據庫底層磁盤文件讀取,數據庫索引實現細節進行了深入的研究,但是沒有串聯起來的講解爲什麼數據庫索引會採用B樹和B+樹而不是其他的數據結構,例如平衡二叉樹、鏈表等,因此,本文打算從數據庫文件存儲以及讀取說起,講解數據庫索引的由來。

我們以拋出問題的形式開始講解:

(1)數據庫文件存儲的方式

數據庫文件存儲都是以磁盤文件存儲在系統中的,這也是數據庫能持久化存儲數據的原因。

(2)從數據庫讀取數據的原理

從數據庫讀取數據,先暫且不考慮從緩存中讀取數據的情況,那就是從磁盤文件中讀取數據的,我們知道從磁盤文件中讀取數據是比較耗時的,數據庫的select操作的時間,取決於執行磁盤IO的次數,因此儘量減少磁盤IO就可以顯著的提升數據的查詢速度。

(3)減少磁盤IO操作的影響因素

有哪些因素可以減少磁盤IO呢,這首先得將瞭解一下磁盤IO與預讀。

磁盤IO與預讀

磁盤讀取依靠的是機械運動,分爲尋道時間、旋轉延遲、傳輸時間三個部分,這三個部分耗時相加就是一次磁盤IO的時間,大概9ms左右。這個成本是訪問內存的十萬倍左右;正是由於磁盤IO是非常昂貴的操作,所以計算機操作系統對此做了優化:預讀;每一次IO時,不僅僅把當前磁盤地址的數據加載到內存,同時也把相鄰數據也加載到內存緩衝區中。

因爲局部預讀原理說明:當訪問一個地址數據的時候,與其相鄰的數據很快也會被訪問到。每次磁盤IO讀取的數據我們稱之爲一頁(page)。一頁的大小與操作系統有關,一般爲4k或者8k。這也就意味着讀取一頁內數據的時候,實際上發生了一次磁盤IO。

正因爲有了磁盤IO預讀機制,所以纔有了減少磁盤IO的可能,因爲一次磁盤IO操作,可以查找到物理存儲中相鄰的一大片數據。

以索引爲B+樹爲例:

磁盤IO次數和索引數據結構查詢的次數以及磁盤IO與預讀都有關係,具體關係:磁盤IO次數 <= B+樹中從根節點一直到葉子節點整個過程中查詢的節點數。

一次磁盤IO操作可以取出物理存儲中相鄰的一大片數據,如果查詢的索引數據(就是B+樹中從根節點一直到葉子節點整個過程中查詢的節點數)都集中在該區域,那麼只需要一次磁盤IO,否則就需要多次磁盤IO

(4)基於磁盤IO預讀機制,索引可以快速查詢數據

到現在纔開始講解索引了。正是基於磁盤IO預讀機制的前提,數據庫可以採用索引機制快速查詢出數據。

(a)什麼是索引

索引是幫助數據高效查詢數據的一種數據結構,它包含一個表中某些列的值以及記錄對應的地址,並且把這些值存儲在一個數據結構中。常用的索引有B樹和B+樹

(b)爲什麼要使用索引

舉個例子來說,假設我們有一個數據庫student,這個表分別有三個字段:name,age,class。假設表中有2000條記錄。

1、假如沒有使用索引,當我們查詢名爲“xiaxia”的學生的時候,即調用:

select name,age,class from student where name = "xiaxia";

此時數據庫不得不在student表中對這2000條記錄一條一條的進行判斷name字段是否爲“xiaxia”。這也就是所謂的全表掃描。

2、而當我們在student表上的name字段上創建索引時,當我們查詢名爲“xiaxia”的學生時:

會通過索引查找去查詢名爲“xiaxia”的學生,因爲該索引已經按照字母順序排列,因此要查找名爲“xiaxia”的記錄時會快很多,因爲名字首字母爲“x”的僱員都是排列在一起的。通過該索引,能獲取到表中對應的記錄。

(5)數據庫中使用什麼數據結構作爲索引

(a)鏈表

鏈表的查詢速度是O(N),每次查詢都得從鏈表頭開始查詢,例如上面查詢“xiaxia”,如果xiaxia在1000的位置,那麼需要遍歷1000次才能查找到。

(b)數組

有人可能會說,查詢速度肯定是數據最快呀,畢竟O(1),的確單純就select的話,採用數組的形式是最合適的,但是採用數組會遇到如下幾個問題:

1、採用數組的話,其他操作如Delete、Update、Insert就不合適了;

2、另外一個原因:索引是存在於磁盤中,當索引非常大的時候,達到幾個G的時候,無法一次加載到內存中。

(c)平衡二叉樹

二叉查找樹查詢的時間複雜度是O(logN),查找速度最快和比較次數最少,既然性能已經如此優秀,但爲什麼實現索引是使用B-Tree而不是二叉查找樹,關鍵因素是磁盤IO的次數。

(d)B樹和B+樹

數據庫索引採用的數據結構

(6)採用平衡二叉樹和B樹,數據查詢的對比

二叉樹查詢過程:

我們先來看二叉樹查找時磁盤IO的次:定義一個樹高爲4的二叉樹,查找值爲10:

第一次磁盤IO:

第二次磁盤IO:

第三次磁盤IO:

第四次磁盤IO:

從二叉樹的查找過程了來看,樹的高度和磁盤IO的次數都是4,所以最壞的情況下磁盤IO的次數由樹的高度來決定。

從前面分析情況來看,減少磁盤IO的次數就必須要壓縮樹的高度,讓瘦高的樹儘量變成矮胖的樹,所以B-Tree就在這樣偉大的時代背景下誕生了。

B-Tree查詢過程:

如下有一個3階的B樹,觀察查找元素21的過程:

第一次磁盤IO:

第二次磁盤IO:

這裏有一次內存比對:分別跟3與12比對

第三次磁盤IO:

B樹的查詢次數少於平衡二叉樹!所以基於B樹以及B+樹的查詢次數少於平衡二叉樹。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章