【Mysql那些事】一文詳解索引原理(全)

學習任何技術,首先我們要知道怎麼用,熟練之後再探究其原理,最後再根據業務進行優化。

                                                                                                                                    ——船長

MySQL的索引有哪些?

主鍵索引:表的主鍵列會默認添加索引,索引中保存了該行記錄的所有數據
唯一索引(upique):該列的所有值必須唯一
普通索引(normal):普通列的一種索引
聚合索引:是普通索引中的一種,但是它是由多個列組成的索引

索引怎麼用?

假設我們有幾張表,如下

使用navicat設計學生student表,並添加索引如下

1、主鍵索引

mysql會爲每個表的主鍵自動添加索引,在其索引樹的葉子節點中,保存着主鍵所在行的所有數據,這個後面會講。也就是說只要找到主鍵,就代表找到了該行記錄,所以使用了主鍵索引速度會比較快

2、唯一索引

唯一索引對應的列,其數據不可重複,這點相當於主鍵,不同的是其索引樹的葉子節點保存的不是所在行的所有數據,而是該列的值,查詢速度比主鍵慢一些

3、普通索引

普通索引就沒什麼好說了,其值可以重複,而且索引樹葉子節點保存的就是該列的值,而不是整行數據

4、聚合索引

當需要聯合幾個字段去查詢時,使用聚合索引的速度會比多個普通索引快,因爲每個索引對應一棵索引樹,多個普通索引,雖然都用上了索引,但是要遍歷好幾個索引樹,而使用聚合索引只需遍歷一棵索引樹

如果對索引樹一點了解都沒有的同學,可以先看看下面的分析,再回過頭來理解一下這四種索引,必然會有煥然一新的感覺

索引的底層結構是什麼?

索引底層結構分爲全文索引、哈希索引、B+樹索引
全文索引:只有MyISAM引擎支持,不作介紹
哈希索引:計算索引列的hashCode,並將其存在索引中,如果出現衝突,就以鏈表的形式存儲,類似hashMap結構
B+樹索引:將索引列的值排序,並放入索引樹中的指定位置(Mysql默認的索引結構)

哈希索引的原理

hash是一種key-value形式的數據結構,哈希索引是以索引列的hashCode爲鍵,數據行的地址指針爲值形成的一種索引,它是一塊非常緊湊的地址空間,可以將其視爲數組

如果我們要查詢【劉備】,那麼先通過計算哈希碼hashCode(劉備)=002得到,然後在哈希索引中找到key=002的位置,拿到真正保存數據的磁盤地址311,再去找到數據行。

可見這裏查找了兩次,第一次是根據hashCode找到地址,第二次是根據地址找到數據行,但是這種查詢速度是非常快的,因爲它沒有去遍歷每一條數據行,而是通過hashCode直接找到數據行的磁盤地址。

那如果發生hash衝突怎麼辦呢?例如關羽和張飛的hashCode都等於010,這時候就會將張飛接在關羽的後面,形成一種鏈式結構,然後在關羽的下一個地址指針中保存張飛的地址。

當查找【張飛】時,通過hashCode(張飛)=010找到地址45,再通過地址找到了關羽,通過判斷姓名【張飛】!=【關羽】,於是通過下一個地址指針46繼續查找,第二次就找到了張飛。

這種解決衝突的方式稱之爲鏈地址法。所以哈希索引的結構就是數組+鏈表的形式,與hashMap雷同,但是當衝突太多導致鏈表很長時,操作數據的時候還是會一直遍歷鏈表才能找到數據,這就會影響性能。

大家可以通過哈希索引的結構,再根據自己平時寫sql用到的條件,思考一下他有什麼優缺點,我將在文末進行總結。

B+樹索引原理

B+樹的演變

二叉樹 ——> 二叉搜索樹 ——> 平衡二叉樹 ——> B樹 ——> B+樹

在這裏對二叉樹等結構不做深入介紹,後續的算法章節會詳細介紹,只簡單介紹B樹和B+樹。

什麼是B樹?

基本定義:

1、根節點至少有兩個子節點

2、葉子節點都在同一高度

3、如果非葉子節點有n個關鍵字,那麼他有n+1個子節點,且這n個節點遞增排列

什麼是B+樹?

B+是由B樹演變而來的,所以它具有B樹的所有特性,另外還有兩點

1、B+樹的非葉子節點只存關鍵字,不存放數據

2、B+樹的葉子節點之間用指針相連,是一個雙向鏈表

MySQL中的B+樹索引

我們用上面的student表來看B+樹是如何存儲索引的,假設在student表中添加以下幾條數據

上面我們已經爲其添加了索引,現在student中的所有索引如下

id:主鍵索引,默認創建的
code:唯一索引
class_id:普通索引
name_class:name列和class_id列的聚合索引

id索引的B+樹索引結構如下:

由此可知,主鍵索引的葉子節點存儲了整行的記錄,所以使用了主鍵索引的sql查詢速度是非常快的。

唯一索引和普通索引一樣,只不過該索引的值是唯一的,不會出現重複值

普通列class_id的索引樹如下:

重點來了!重點來了!重點來了!

可見其葉子節點保存的是其行記錄中的id,我們看下面兩條sql有何不同

sql1:select * from tb_student where class_id=834

sql2:select id from tb_student where class_id=834

看似一樣,實則不然。第一條sql查詢的是整行記錄,而行記錄是保存在主鍵的索引樹中的,所以其查詢步驟是:根據普通索引class_id的索引樹找到葉子節點,獲得行記錄id,然後根據id去主鍵索引樹中取出整行記錄

這個查詢過程就稱之爲回表,可見回表會降低查詢效率

而第二條sql查詢的就是id,class_id的索引樹葉子節點保存的就是id的值,那麼不需要去主鍵索引樹取值了,直接將id返回即可,所以效率較前者高。(看到這裏大家應該能想到爲什麼需要聚合索引了)

知其然,知其所以然,必百戰百勝。

下面我們再看看聚合索引的樹結構:

爲了數據能夠直觀一點,我們新增一個聚合索引

其索引樹如下

聯合索引中的第一個索引是classid,那麼索引樹會先根據class_id去排序,而後再依次根據後面的索引列排序。所以聯合索引的最左原則就可以在此體現了。

SELECT * FROM tb_student where class_id=18 and id=834

對於上面這條語句,他有兩個索引可以走,第一是聯合索引id_class,第二個是主鍵索引id,拿到底會走哪一條呢?答案是主鍵索引

注意:聯合索引和主鍵索引同時存在時,優先走主鍵索引

爲什麼呢?這是mysql採用的優化策略,因爲主鍵索引可以直接查出整行數據,所以不管你select *還是select 其他字段我都能滿足,而走聯合索引且select *時還會涉及到一次回表操作

總結

哈希索引的優缺點

優點:
1、查詢速度快
2、維護索引的成本相對較低

缺點:
1、無法進行範圍查詢,因爲是通過計算元素的hashCode定位查找的,像age>50這種範圍查找是無法使用哈希索引的
2、無法通過索引排序,哈希的最大特點就是散列分佈,幾乎毫無規律,所以無法排序

B+樹索引的優缺點

優點:
1、索引樹一般2-4層,查詢效率高,IO消耗少
2、支持各種範圍查詢
3、支持索引排序

缺點:
1、維護索引樹的代價高
2、索引太多所佔的空間也會變大

 

關注公衆號:全棧船長

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