深入理解mysql索引底層數據結構與算法

索引到底是什麼

索引是幫助Mysql高效獲取數據的一種數據結構

索引儲存在哪裏

和數據一樣,索引以文件形式儲存在硬盤上,在MyISAM儲存引擎中,數據和索引文件試試分開儲存的。

 

MyISAM文件儲存示意圖

 

在InnoDB中,數據和索引文件是合起來儲存的,注意下圖中沒有了I(index)結尾的文件。

 

InnoDB文件儲存示意圖


後面會進一步分析爲什麼會這樣

索引的數據結構

想想JDK8的Hashmap中,當鏈表長度大於一定限度時,爲了能夠高效的檢索數據,引入了紅黑樹。索引的思想也是這樣,通過一種數據結構高效的數據結構來加速數據檢索的過程。
想想以下這幾種常用的數據結構可否用於索引呢?
1. BST
2. 紅黑樹
3. Hash

BST在節點有序的情況下會變成一種線性結構,複雜度退化到O(n),顯然是不行的。
紅黑樹解決了平衡的問題,但是在數據量比較大的情況下,紅黑樹的高度太高,導致磁盤IO次數過多,也不夠合理。
Hash似乎解決了磁盤IO的問題,但是Hash有大量衝突的時候還是線性遍歷,最關鍵的是限制太多,例如無法支持範圍查詢,也不支持部分索引匹配。

B+樹

B-樹

B+樹

比起紅黑樹,上面兩種數據結構都更加矮胖。他們兩之間一個很大的不同是B+樹的節點上不儲存value,只儲存key,而葉子節點上儲存了所有kv集合,並且節點之間都是有序的。

這樣的好處是每一次磁盤IO能夠讀取的節點更多,也就是樹的度可以設置的更大一些,因爲每次磁盤IO讀取的磁盤頁數是一定的,例如每次磁盤IO能夠讀取1頁=4kb,那麼省去value的情況下同樣一頁數據能夠讀取更多的key,這樣就大大減少了磁盤的IO次數。

此外,B+樹是排序好的數據結構,數據庫中><或者order by等都可以直接依賴這一特性。

MyISAM索引實現(非聚集索引)

MyISAM中索引和數據是分開儲存的,並且主鍵索引和輔助索引(二級索引)的儲存方式是一樣的。

 

主鍵索引

輔助索引

InnoDB索引實現(聚集索引)

InnoDB中索引文件和數據文件是同一個文件。並且主鍵索引和二級索引儲存方式有所不同,如圖所示,二級索引的葉子節點不儲存數據,僅儲存主鍵ID。

 

主鍵索引

輔助索引

這裏思考兩個問題

  1. InnoDB表中必然有主鍵,爲什麼最好一定是有序自增id?
  2. 爲什麼二級索引葉子節點儲存的是主鍵值?

問題一:如果id是無序的,那麼很有可能新插入的值會導致當前節點分裂,此時MySQL不得不爲了將新記錄插到合適位置而移動數據,甚至目標頁面可能已經被回寫到磁盤上而從緩存中清掉,此時又要從磁盤上讀回來,這增加了很多開銷,同時頻繁的移動、分頁操作造成了大量的碎片,得到了不夠緊湊的索引結構,後續不得不通過OPTIMIZE TABLE來重建表並優化填充頁面。
反之,如果每次插入有序,那就會在當前頁後面連續寫入,寫不下就會重新分配一個節點,內存都是連續的,這樣效率自然也就最高了。

問題二:如果二級索引儲存的也是數據,那麼每次插入mysql都不得不更新每棵索引樹,這樣就加劇了新增編輯時的性能損耗,並且這樣一來空間利用率也不高,產生了大量冗餘數據。

聯合索引

聯合索引底層數據結構長什麼樣?

聯合索引示意

比較相等時,先比較第一列的值,如果相等,再繼續比較第二列,以此類推。

最左前綴原理

使用聯合索引時,索引列的定義順序將會影響到最終查詢時索引的使用情況。例如聯合索引(a,b,c),mysql會從最左邊的列優先匹配,如果最左邊的帶頭大哥沒有使用到,在未使用覆蓋索引的情況下,就只能全表掃描。
聯合底層數據結構思考,mysql會優先以聯合索引第一列匹配,此後纔會匹配下一列,如果不指定第一列匹配的值,也就無法得知下一步查詢哪個節點。
另外還有一種情況,如果遇到 > < between等這樣的範圍查詢,那B+樹中也就無法對下一列進行等值匹配了。

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