mysql數據庫索引實現原理
1. B-樹
在介紹索引實現之前,我們先來了解下幾種樹的數據結構。
二叉搜索樹
二叉搜索樹有以下性質
1.每個節點有一個關鍵字
2.左右孩子至多有一個。
3.關鍵字大於左孩子,小於右孩子。
正因為二叉搜索樹的特性,所以這種數據結構很適合用來做搜索,效率等同於二分查找,時間復雜度為log2(n),
但是這種最原始的二叉樹有一個弊端,在極端的情況下會退化成鏈表
所以基礎二叉搜索樹有很多變種,例如紅黑樹和AVL樹,基於特定的策略避免了樹退化成鏈表,紅黑樹做數據量不大的搜索還是應用很廣泛的,但是要基於文件索引系統。卻不合適,因為紅黑樹雖然搜索效率高,但是樹的高度比B-樹和B+樹要高,需要進行的磁盤IO就多,相比之下后者優勢就比較明顯了。
2.B-樹
一種多路搜索樹,不是二叉樹
我們來看一個m階B樹
它有如下幾個性質
1.根節點至少有2個孩子,根節點孩子數為[2,m]。
2.除根節點外每個非葉子節點的孩子數為[m/2,m](向上取整)。
3.非葉子節點的關鍵字個數=指向孩子的指針樹-1。
4.所有葉子節點在同一層且關鍵字個數為k-1, 其中 m/2 <= k <= m
5.節點之間關鍵字的大小,類比二叉搜索樹,即關鍵字的值按大小排列,pi的關鍵字的值屬於(k[i],k[i+1])開區間,例如 p2的關鍵字要大於17,小於35。
圖片來自網絡
B樹相對與二叉搜索樹來說,變得矮胖,這樣能減少io讀取的次數,其搜索效率也是log2(n)但這還不足以用來做文件索引。因為B樹有可能在非葉子節點命中數據,耗費存貯。所以文件索引一般用B+樹。
3.B+樹
B+樹建立在B-樹的基礎之上,更改了幾條性質
1.非葉子節點的關鍵字和孩子指針數相同
2.pi的關鍵字的值屬於[k[i],k[i+1]]閉區間。
3.為葉子節點添加一個指針
圖片來自網絡
B+樹在B-樹的基礎上添加了葉子鏈表指針,方便查找相鄰的數據。
所有數據只有在葉子節點才會被命中,非葉子節點只提供索引,這樣非葉子節點可以存貯更多的數據,索引B+樹很適合做文件索引,
4.Mysql的B+索引實現原理
mysql存貯索引的文件以頁為單位,一個節點相當於一頁。不同的存貯引擎,索引實現也不同,就以innodb來說,默認一個索引頁為16K,mysql在查詢索引時,會預先把多個頁加載到內存中,所以如果索引的鍵很大的話,會引起索引的列表,產生很多的碎片,因為如果一頁存儲不下一個節點的話,就會新開另外一頁。
4.1索引查找模擬
首先我們看下mysql索引能存貯多少數據,
一頁為16K,
1.我們假設以int(4B)大小的自增主鍵,一個子節點指針為6B
2.行數據大小假設為1KB
第一層:根節點
161024/(4+6)≈1638個索引鍵
第二層:非葉子節點
如果第二層也只存索引鍵,16381638≈2683044,能存200多萬個索引鍵。
第三層如果只存數據:一頁能存16行數據
1638163816=42928704,
三次io能查詢4000多萬數據,這就是為什么數據庫為什么采取B+索引的原因,因為能減少IO的讀取次數。
InnoDB使用的是聚簇索引,即數據文件就是索引文件,這里又分主鍵索引和非主鍵索引。
主鍵索引:將主鍵映射到B+樹中,而葉子節點就是行數據。
非主鍵索引:存貯的是主鍵值,再通過主鍵的值,去搜索主鍵索引獲得數據。
MyISM使用的是非聚簇索引:即索引文件和數據文件分開,葉子節點僅僅存貯了數據文件的地址。這點和oracle的B樹索引實現類似,都是存貯了地址。myIsm的主鍵索引和非主鍵索引沒什么區別,只是存貯的鍵值列不同,葉子節點都是存貯的數據地址。