爲了講清楚這個問題,阿粉先帶你們瞭解一下什麼是索引。sql
我記得剛剛學習數據庫的時候,老師喜歡用書本的目錄來類比數據庫的索引,並告訴咱們索引可以像目錄同樣,讓咱們更快地找到想要找到的數據。數據庫
若是是第一次接觸索引,這個比喻可以讓咱們有一個直觀的印象。可是當深刻去學習索引的時候,咱們不能繼續持有索引即目錄的思想,咱們要跳出來去思考索引的本質是什麼。數組
在沒有索引的狀況下,咱們查找數據只能按照從頭至尾的順序逐行查找,每查找一行數據,意味着咱們要到到磁盤相應的位置去讀取一條數據。網絡
若是把查詢一條數據分爲到磁盤中查詢和比對查詢條件兩步的話,到磁盤中查詢的時間會遠遠大於比對查詢條件的時間,這意味着在一次查詢中,磁盤io佔用了大部分的時間。更進一步地說,一次查詢的效率取絕於磁盤io的次數,若是咱們可以在一次查詢中儘量地下降磁盤io的次數,那麼咱們就能加快查詢的速度。數據結構
在知道了減小磁盤io能加快查詢速度後,咱們就要聚焦於如何減小磁盤io。若是按照原表逐行查詢的話,n條數據就要查詢n次,也就是O(N)的時間複雜度,爲了減小磁盤io的次數,咱們必須用一種查詢時間複雜度更低的數據結構來保存數據。性能
這種查詢時間複雜度低的數據結構,咱們稱之爲索引。因此通俗來講,索引其實就是某種數據結構,能充當索引的數據結構是多種多樣的。學習
既然索引是一種便於查詢的數據結構,若是你們對數據結構有必定了解的話,大機率會首選樹型結構。畢竟樹型結構廣泛有着O(logN)的查詢時間複雜度,並且插入刪除數據的性能也比較平均。(可能你會說數組,哈希表的查詢速度也很高啊,這個後面也會分析)大數據
雖然咱們都已經知道Mysql中最經常使用的引擎像InnoDB和MyISAM,最終都選擇了B+樹做爲索引,可是這裏我仍是打算從最多見的二叉樹開始講起,推導一下爲何最終選擇了B+樹做爲索引,並比較一下幾種樹型結構在充當索引時的優劣。優化
最普通的二叉樹的問題在於他不能保證O(logN)的查詢時間複雜度,咱們看下面的圖:spa
因爲插入的元素逐漸增大,元素始終在右邊進行插入,好好的一棵二叉樹最終變成了一條「鏈表」。在這種極端的狀況下,二叉樹的查詢時間複雜度再也不是O(logN),而是退化爲O(N),這樣顯然不符合索引的要求。
像紅黑樹這樣的平衡二叉樹,不管如何插入元素,他均可以經過一些旋轉的方法調整樹的高度,使得整棵樹的查詢效率維持在O(logN),以下圖所示:
這麼來講他已經符合了成爲索引的必備條件,可是最終沒有選擇他做爲索引說明還有不足的地方。仔細看看能夠發現平衡二叉樹的每一個節點只有兩個孩子節點,若是一張表的數據量特別大,整棵樹的高度也會隨之上升。一個千萬級別的表若是用平衡二叉樹做爲索引的話,樹高將會達到二十多層。這也就意味着作一次查詢須要二十屢次磁盤io,這是一個不小的開銷。
那麼有沒有能在大數據量的狀況下,還能保持一個較小樹高的樹型結構呢?
答案就是B樹。上面咱們說到了平衡二叉樹的瓶頸在於一個節點只有兩個孩子節點,而B樹一個節點能夠存放N個孩子節點,這就完美解決了樹高的問題,咱們能夠把B樹稱爲平衡多叉樹,B樹做爲索引以下圖所示:
圖片來源網絡
可是以B樹的結構做爲索引仍有能夠優化的地方,咱們先看看最終的B+樹,再仔細分析B+樹在B樹的基礎上做了哪些改進,爲何B+樹最終可以勝任索引的工做:
圖片來源網絡
從圖片中能夠看到B+樹一樣是一棵多叉平衡樹,和B樹同樣很好地解決了樹高的問題。
但仔細看能夠發現,B樹的節點中既存儲索引,也存儲表對應的數據;而B+樹的非葉子節點是不存儲數據的,只存儲索引,數據所有存儲在葉子節點上。
爲何要作這樣的改進?咱們作一次算術就知道了。
假設樹高爲2,主鍵ID爲bigint類型,長度爲8字節,節點指針爲6字節,一行數據記錄的大小爲1k,一次io操做能得到一頁16k的數據。
在索引爲B+樹的狀況下,根節點能存儲:16k / (6 + 8) = 1170 條索引指針;到了第一層,一共能指向 1170 * 1170 = 1368900 條索引指針;到了最底一層葉子節點,一個節點能存儲16k / 1k = 16 條記錄,一共能存儲 1170 * 1170 * 16 = 21902400 條記錄
在B樹的狀況下,因爲非葉子節點使用了大量空間存儲數據,存放的索引指針確定就少,最終整棵樹若是想要存儲和B+樹同樣多的數據就必需要增長樹高,這樣一來就增長了磁盤io,因此說B+樹做爲索引的性能比B樹高。
葉子節點之間使用指針鏈接,提升區間訪問效率。若是咱們要進行範圍查詢,能夠輕鬆經過B+樹葉子節點之間的指針進行遍歷,減小了沒必要要的磁盤io。
看到這裏,相信你們對爲何Mysql的經常使用引擎都默認使用B+樹做爲索引已經有了初步的認知。咱們只要牢記一點:索引是爲了減小磁盤io提升查詢性能而存在的。
最後迴應一下爲何不經常使用哈希表和數組做爲索引
哈希表雖然單一個值的查詢效率很高,可是撐不住範圍查詢,哪一個公司的業務還沒個範圍查詢呢?
而數組雖然查詢的效率高,可是增長和刪除的效率低,因爲記錄在增長和刪除的時候索引也得跟着維護,這會致使大數據量的狀況下,增長或刪除一條記錄效率較低。