MySQL爲何不用數組、哈希表、二叉樹等數據結構做爲索引呢

掃描下方二維碼或者微信搜索公衆號菜鳥飛呀飛,便可關注微信公衆號,閱讀更多Spring源碼分析Java併發編程Netty源碼系列文章。web

微信公衆號

前言

在上一篇博客中詳細說明了 MySQL 的索引使用的是 B+Tree 這種數據結構,而不是 B-Tree,然而平時咱們接觸到了不少高效的數據結構,例如數組、哈希表、二叉搜索樹、紅黑樹等,那爲何 MySQL 不選擇這些數據結構做爲索引呢?redis

MySQL 做爲存儲數據的組件,它的主要操做就是數據的增刪改查,其中查詢操做又是重中之重。咱們常常所說的數據庫優化,大部分優化的就是查詢相關的操做。所以一個數據庫選擇何種數據結構做爲索引,主要考慮因素就是這種數據結構對增刪改查操做的效率如何,尤爲是查詢操做(一般查詢操做包括等值查詢、範圍查詢等)。本文接下來將從增刪改查的角度來分析,爲何 MySQL 最終選用的是 B+Tree 做爲索引的數據結構。數據庫

由於 MySQL 在 5.5 版本之後,默認的存儲引擎是 InnoDB,因此本文所討論的內容,全是基於存儲引擎是 InnoDB 爲前提。編程

數組

數組這種數據結構,應該是咱們接觸編程起,最早遇到的數據結構了。數組是內存中一塊連續的內存空間,定義一個數組對象,這個對象的指針指向了這塊內存的起始地址,若是知道數組元素的下標,那麼就能夠計算出該下標所對應的元素的內存地址了,所以能夠在 O(1)的時間複雜度內獲取到元素,很是快速。數組

對於一個有序數組,它的查找過程可使用二分查找法進行查找,時間複雜度爲 O(logn),效率也很是高。由於是有序數組,所以對範圍查找也十分友好,只須要找到起始元素便可。若是在知道元素下標的狀況下,更新操做也很是快,對於刪除操做,若是咱們不考慮空洞的話(若是直接將對應下標處的元素置爲 null,這樣這塊連續內存塊中至關於有個空洞),刪除操做也很快。微信

這麼一分析,數組對查詢、刪除、更新操做的效率很是高,選數組做爲 MySQL 索引的數據結構看起來彷佛不錯。然而咱們忽略了還有插入操做,若是咱們要往數組中間插入一個數據,咱們須要將數組中要插入的目標位置後的全部元素先日後挪動一個位置,而後才能插入新的數據,也就是涉及到了數組的複製操做,要插入的數據越靠前,那麼咱們須要複製的數據就越多,這個不只須要額外開闢內存,複製數據消耗的時間也很長。而咱們在平時的開發中,生產環境的一張表的大小動輒就 1GB 以上了,若是要往中間插入一條數據時,那得複製多少數據啊!數據結構

所以,從插入數據這一角度來看,數組不太適合做爲 MySQL 索引的數據結構。併發

哈希表

哈希表是一種 key-value 形式的數據結構,底層採用數組+鏈表結構來實現,它是將 key 經過一個哈希函數計算出一個數字,而後以該數字做爲數組的下標,而後將 value 存放到對應下標的數組中。對於不一樣的 key,在通過哈希函數計算後,可能出現相同的值,這種狀況叫作哈希衝突,這時候就意味着同一個數組下標處要存放兩個元素了,因此這個時候將數組中的元素變爲一個鏈表,經過鏈表將這兩個元素串聯起來。編輯器

根據上面哈希表的特色來看,哈希表對於刪除、查找、更新、插入操做,都是先根據 key 計算出一個值,就能定位到數據的目標位置了,時間複雜度都是 O(1),速度特別快。可是咱們在使用 MySQL 時,常常會遇到查找某個範圍內的數據,例如 between...and、>=、<=等範圍查找操做。這個時候哈希表應該怎麼辦呢?函數

由於哈希表的全部 key 都會通過哈希函數計算,而後再存放數據,原本可能有序的 key,但通過哈希函數計算出來的值就不是有序的了,因此這個時候,若是要在哈希表中進行範圍查找,就只能對整個哈希表進行遍歷了,只有符合條件範圍的數據,才取出來。當咱們數據庫中的數據愈來愈多,達到幾百萬甚至幾千萬條的時候,這個時候,對整個表的遍歷是很是耗時的。

所以,從範圍查詢的場景來看,哈希表也不太適合做爲 MySQL 索引的數據結構。哈希表適用於什麼場景呢?適用於等值查詢的場景,最經典的場景就是 NOSQL 數據庫,例如咱們最經常使用的 redis,redis 中不就是全都是 key-value 嗎?

實際上,MySQL 中也有地方使用哈希做爲索引。使用 MySQL 的同窗大部分都應該使用過 Navicat 這款工具吧,這是一個可視化的 MySQL 客戶端遠程鏈接工具,在這個工具中,咱們能夠在可視化界面中進行數據庫的相關操做,例如增刪改查、修改表結構、建立索引等。在建立索引時,咱們其實能夠選擇索引的數據結構,它有兩個選項:B+Tree 和 HASH,若是你不勾選,默認狀況下是 B+Tree。以下圖所示。

圖1

一般狀況下,不建議將索引的結構選爲 HASH,除非業務的場景的確符合 key-value 這種場景,例如業務系統的一些 key-value 形式的配置項的表、數據字典等功能。

二叉樹

每一個節點最多有兩個子結點的樹稱之爲二叉樹,比較特殊且經常使用的二叉樹有二叉搜索樹、AVL 樹(平衡樹)、紅黑樹等。

對於二叉搜索樹而言,它的查找操做的時間複雜度就是樹的高度,最理想的狀況下,也就是滿二叉樹的狀況下,查找的時間複雜度爲 O(logn)。當咱們在不停地動態地往樹中插入數據、刪除數據時,在極端狀況下,二叉搜索樹可能退化成鏈表,它的查找時間複雜度就變成了 O(n),性能不夠穩定。

平衡樹是在二叉查找樹的基礎上,增長了一條限制,左右兩個子樹的高度差不能超過 1,左右兩邊相對平衡,所以稱之爲平衡樹。而平衡樹在數據動態地刪除、插入地過程當中,爲了維護平衡,避免樹退化成鏈表,所以須要在刪除或者插入數據後進行額外的旋轉操做,會損耗必定的性能,但總體來說,它的查找、刪除、插入、更新的複雜度均爲 O(logn)。它的中序遍歷,數據是有序的,所以也適合範圍查找。可是它的缺點是,爲了維護平衡,它的旋轉操做過於複雜。

在平衡二叉樹的基礎上又出現了紅黑樹,關於紅黑樹的性質就在這裏不細說了,內容太多了,後面會單獨寫博客介紹。總體上來講,紅黑樹是一種近似平衡(不徹底平衡),結點非黑即紅的樹,它的樹高最高不會超過 2logn,所以查找的時間複雜度爲 O(logn),不管是增刪改查,它的性能都十分穩定。工程上,不少地方都使用的是紅黑樹這種數據結構,例如 Java 中的 HashMap、TreeMap 等。

咋一看,AVL 樹和紅黑樹的增刪改查性能都十分穩定,雖然中間涉及到不少旋轉操做,實現過於複雜,可是仍是能用代碼實現出來的,只要能實現出來,這都不是事啊,性能好、夠穩定就行,那爲何不用 AVL 樹和紅黑樹去做爲 MySQL 的索引數據結構呢?

這是由於不管是二叉搜索樹,仍是 AVL 樹,亦或是紅黑樹,它們都是二叉樹的一種,特色都是每一個結點最多隻有兩個子結點,若是存儲大量數據的話,那麼樹的高度會很是高。而 MySQL 存儲的數據最終是要落地到磁盤的,MySQL 應用程序讀取數據時,須要將數據從磁盤先加載到內存後才能繼續操做,因此這中間會發生磁盤 IO,而若是樹過高,每遍歷一層結點時,就須要從磁盤讀取一次數據,也就是發生一次 IO,若是數據在樹高爲 20 的地方,那查找一次數據就得發生 20 次 IO,這對應用程序簡直就是災難性的,耗時太長了。所以二叉樹在 MySQL 這種須要存儲大量數據的場景下,是不適合當作索引的數據結構的,由於樹過高,操做數據時會發生屢次磁盤 IO,性能太差。

B-Tree 與 B+Tree

既然二叉樹由於每一個結點最多隻有兩個子結點,最終在存儲大量數據時致使樹高過高,所以不適合當作 MySQL 的索引,那麼讓樹的每一個結點儘量多的擁有多個子結點,也就是多叉樹,那這樣在大量儲存數據時,樹高就低不少了,那這樣總應該能夠了吧!而多叉樹中典型的例子有 B-Tree 和 B+Tree。

B-Tree 的特色是不管葉子結點和非葉子結點,它都存有索引值和數據;B+Tree 的特色是隻有葉子結點纔會存放索引值和數據,非葉子結點只會存放索引值自己。所以對於非葉子結點,一個結點中,B+Tree 存放的索引值數量會遠遠大於 B-Tree(由於一個結點的空間是有限的,B-Tree 要存放索引+數據,而 B+Tree 只須要存放索引),這樣就致使了每一個結點中,B+Tree 能向下分出更多的叉,子結點數更多。

那麼在要存儲一樣大小的數據文件的場景下,用 B+Tree 存儲,最終樹的高度會遠遠小於用 B-Tree 存儲的高度,因此使用 B+Tree 做爲 MySQL 索引的數據結構,未來在讀取數據時,發生的磁盤 IO 次數會更少,性能更優,所以最終 MySQL 索引的數據結構使用的是 B+Tree。

若是你想更加詳細的瞭解 B+Tree 和 B-Tree 的知識,能夠閱讀如下這兩篇文章:索引數據結構之 B-Tree 與 B+Tree(上篇)索引數據結構之 B-Tree 與 B+Tree(下篇)

其中《索引數據結構之 B-Tree 與 B+Tree(下篇)》這篇文章的後半部分,花了很長的篇幅,說明了爲何 MySQL 要使用 B+Tree 而不是 B-Tree 來做爲索引的數據結構。

總結

本文從每一種數據結構的特色出發,詳細分析了爲何 MySQL 最終要選用 B+Tree 做爲索引的數據結構,但如今爲止,相信你應該對 MySQL 的索引有了必定的瞭解。在平時接觸 MySQL 的過程當中,相信你必定據說過不少索引名詞,例如:主鍵索引、聚簇索引、非聚簇索引、二級索引、惟一索引、覆蓋索引、全文索引、聯合索引等等,那你知道它們分別是什麼意思嗎?下一篇文章介紹。

參考資料

  1. 極客時間林曉斌《MySQL 實戰 45 講》。

相關推薦

微信公衆號
相關文章
相關標籤/搜索