程式設計師的演算法課(16)-B+樹在資料庫索引中的作用
前文講了二叉樹和多路樹,二叉樹的效能很好,像AVL樹、紅黑樹都是很優秀的結構,那麼在資料庫索引中,並沒有採用二叉樹這種結構,這是為什麼呢?因為,有效能更好的樹來做搜尋!目前大部分資料庫系統及檔案系統都採用B-Tree或其變種B+Tree作為索引結構。
一、B-樹和B+樹回顧
1.B-樹
B-tree(多路搜尋樹)是一種常見的資料結構。使用B-tree結構可以顯著減少定位記錄時所經歷的中間過程,從而加快存取速度。按照翻譯,B 通常認為是Balance的簡稱。這個資料結構一般用於資料庫的索引,綜合效率較高。
B-樹每個節點都儲存key和data,所有節點組成這棵樹,並且葉子節點指標為null。
B-樹的特徵:
- 根節點至少有兩個孩子
- 每個非根節點有[ ,M]個孩;
- 每個非根節點有[ -1,M-1]個關鍵字,並且以升序排列
- key[i]和key[i+1]之間的孩子節點的值介於key[i]、key[i+1]之間
- 所有的葉子節點都在同一層
B-樹的優勢:
B樹的優勢在於多路查詢,這便是優於紅黑樹的具體原因,大家想一想,B-樹每個結點有多個key,而紅黑樹每個結點有一個key,那麼隨著資料的不斷增多,紅黑樹的高度不斷增加,效率不斷降低,而B樹的高度一般都很低,為甚?因為B樹一個結點可以放N個key,,只有都滿了才分裂一次!B樹為什麼會分裂呢? 因為隨著資料的增多,一個結點的key滿了,為了保持B樹的特性,就會產生分裂,就像紅黑樹和AVL樹為了保持樹的性質需要進行旋轉是一樣一樣的!
2.B+樹
B+樹是B-樹的變體,也是一種多路搜尋樹,其定義基本與B樹相同。B+樹上的葉子結點儲存關鍵字以及相應記錄的地址,葉子結點以上各層作為索引使用。
B+樹:只有葉子節點儲存data,葉子節點包含了這棵樹的所有鍵值,葉子節點不儲存指標。
B+樹的特徵:
- 所有關鍵字都出現在葉子結點的連結串列中(稠密索引),且連結串列中的關鍵字恰好是有序的;
- 不可能在非葉子結點命中;
- 非葉子結點相當於是葉子結點的索引(稀疏索引),葉子結點相當於是儲存(關鍵字)資料的資料層;
- 更適合檔案索引系統;
B+Tree與B-樹的不同:
- 每個節點的指標上限為2d而不是2d+1;
- 內節點不儲存data,只儲存key,即所有關鍵字都在葉子結點出現;
- 葉子節點不儲存指標,而是為所有葉子結點增加一個鏈指標。
B+樹的優勢:
在B+樹上增加了順序訪問指標,也就是每個葉子節點增加一個指向相鄰葉子節點的指標,這樣一棵樹成了資料庫系統實現索引的首選資料結構。 原因有很多,最主要的是這棵樹矮胖,一般來說,索引很大,往往以索引檔案的形式儲存的磁碟上,索引查詢時產生磁碟I/O消耗,相對於記憶體存取,I/O存取的消耗要高几個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查詢過程中磁碟I/O操作次數的時間複雜度。樹高度越小,I/O次數越少。 那為什麼是B+樹而不是B樹呢,因為它內節點不儲存data,這樣一個節點就可以儲存更多的key。
二、索引搜尋速度的決定性因素是什麼?
因為資料庫的大部分資料都是存在磁碟上面的,一般來說,索引本身也很大,不可能全部儲存在記憶體中,因此索引往往以索引檔案的形式儲存的磁碟上。這樣的話,索引查詢過程中就要產生磁碟I/O消耗,相對於記憶體存取,I/O存取的消耗要高几個數量級,所以評價一個數據結構作為索引的優劣最重要的指標就是在查詢過程中磁碟I/O操作次數的時間複雜度。樹高度越小,I/O次數越少。換句話說,索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數。
二叉樹的高度過深進行多次磁碟IO,導致查詢效率低下,而B樹和B+樹樹中每個結點最多含有m個孩子,所以相對二叉樹,B-樹和B+樹的高度比較低,顯得又矮又胖!
三、MySQL中的儲存引擎
在MySQL中,最常用的兩個儲存引擎是MyISAM和InnoDB,它們是MySQL的兩代搜尋引擎。
它們對索引的實現方式不同,MyISAM data存的是資料地址,索引和資料分開的。InnoDB data存的是資料本身,索引也是資料。
索引分為主索引和輔助索引:一般以主鍵為索引的叫做主索引,而以其他鍵為索引的叫做輔助索引。
四、MyISAM利用B+樹實現
主索引:
由上圖可以看出,col1是主鍵,而葉子結點儲存的資料是一個地址,通過地址找到資料。
輔助索引(和主索引不同的是輔助索引的key是可以重複的) :
五、InnoDB利用B+樹實現
主索引:
注意,和MyISAM不同的是葉子結點的資料域儲存的是全部資料。
輔助索引:
仔細看輔助索引和主索引的區別,輔助索引的葉子結點儲存的是主鍵;這就是MyISAM和InnoDB最大的不同。
六、InnoDB到底比MyISAM好在哪裡?
既然MyISAM和InnoDB是MySQL的兩代引擎,肯定會有一個提升,而InnoDB是最新一代,那麼它到底優在哪裡?
試想,MyISAM和InnoDB都是以B+樹為基礎實現的,相對於B樹的不同其實前面已經講過,即資料域和結點分離;
而MyISAM更是索引和檔案分離,B+樹的葉子結點的資料域存放的是檔案內容的地址,主索引和輔助索引的B+樹都是如此,那麼如果我改變了一個地址,是不是所有的索引樹都得改變,正如前面我們講的在磁碟上頻繁的讀寫操作是效率很低的,而這塊又不適用區域性原理,因為邏輯上相鄰的結點,物理上不一定相鄰,那麼這樣就會造成效率上的降低;
於是乎,InnoDB就產生了,它讓除了主索引以外的輔助索引的葉子結點的資料域都儲存主鍵,先通過輔助索引找到主鍵,然後通過主鍵找到葉子結點的所有資料,聽起來貌似很麻煩,遍歷了兩棵樹,但是,這樣如果有了修改的話,改變的只是主索引,其它輔助縮印都不用動,而且,資料庫中的樹的每一個結點的key可不是咱們給的那麼少,試想如果一個結點有1024個key,那麼高度為2的B+樹都有1024*1024個key,所以一般樹的高度都很低,所以,遍歷樹的消耗幾乎忽略不計!
七、總結
1.為什麼使用B+樹?
- 檔案很大,不可能全部儲存在記憶體中,故要儲存到磁碟上
- 索引的結構組織要儘量減少查詢過程中磁碟I/O的存取次數(為什麼使用B-/+Tree,還跟磁碟存取原理有關,具體看下邊分析)
- 區域性性原理與磁碟預讀,預讀的長度一般為頁(page)的整倍數,(在許多作業系統中,頁得大小通常為4k)
- 資料庫系統巧妙利用了磁碟預讀原理,將一個節點的大小設為等於一個頁,這樣 每個節點只需要一次I/O 就可以完全載入,(由於節點中有兩個陣列,所以地址連續)。而紅黑樹這種結構, h 明顯要深的多。由於邏輯上很近的節點(父子)物理上可能很遠,無法利用區域性性。
2.為什麼B+樹比B樹更適合做索引?
B+樹磁碟讀寫代價更低
B+的內部結點並沒有指向關鍵字具體資訊的指標,即內部節點不儲存資料。因此其內部結點相對B 樹更小。如果把所有同一內部結點的關鍵字存放在同一盤塊中,那麼盤塊所能容納的關鍵字數量也越多。一次性讀入記憶體中的需要查詢的關鍵字也就越多。相對來說IO讀寫次數也就降低了。
B+-樹的查詢效率更加穩定
由於非終結點並不是最終指向檔案內容的結點,而只是葉子結點中關鍵字的索引。所以任何關鍵字的查詢必須走一條從根結點到葉子結點的路。所有關鍵字查詢的路徑長度相同,導致每一個數據的查詢效率相當。
3.MySQL兩種索引MyISAM和InnoDB的區別
- MyISAM是非事務安全的,而InnoDB是事務安全的
- MyISAM鎖的粒度是表級的,而InnoDB支援行級鎖
- MyISAM支援全文型別索引,而InnoDB不支援全文索引
- MyISAM相對簡單,效率上要優於InnoDB,小型應用可以考慮使用MyISAM
- MyISAM表儲存成檔案形式,跨平臺使用更加方便
- MyISAM管理非事務表,提供高速儲存和檢索以及全文搜尋能力,如果在應用中執行大量select操作可選擇
- InnoDB用於事務處理,具有ACID事務支援等特性,如果在應用中執行大量insert和update操作,可選擇。
我的微信公眾號:架構真經(id:gentoo666),分享Java乾貨,高併發程式設計,熱門技術教程,微服務及分散式技術,架構設計,區塊鏈技術,人工智慧,大資料,Java面試題,以及前沿熱門資訊等。每日更新哦!
參考資料: