03-看透索引本質這一篇就夠了

本來標題是“03-MySQL優化系列之後-看透索引本質,理清B-tree和B+tree”,但是發現居然是“零推薦”,其他技術含量一般的文章,反而推薦好幾千,試試換換標題看看推薦量有沒有變化。

我們常常聽說,要提高數據庫的查詢速度,就要添加索引,可是細想以下三個問題,你是否能講清楚?

1,索引究竟是什麼?

2,為什麼索引可以提高查詢效率?

3,既然索引這麼好,那麼我所有的字段都加索引好了,這樣不就世界都美好了嗎?

搞清楚這三個問題,基本上你對索引的認識就差不多了,閱讀完本文,相信你對三個問題會非常清晰。

下面,我們一一來探索交流。

1,什麼是索引

你可能常見的說法是,索引是指一本書的目錄,其實這是一種近似的說法,但不是十分準確。

確切來說,索引是存儲引擎用於快速找到記錄的一種數據結構,是對查詢性能優化最有效的手段。

2,索引到底是一種什麼樣的數據結構?為什麼可以提高查詢效率?

MySQL索引的底層數據結構,主要有兩種,一種是B+tree,一種是哈希。

3,那兩種數據結構,我們究竟採用哪種?

其實從定位來說,哈希完勝B+tree,因為哈希的時間複雜度是O(1),但是我們的業務系統開發場景中,更多是這樣的情況,比如where id>10或者where age>18等等,大家會發現,此類方式,更多是一種範圍查找,而這個就是哈希的軟肋,因為哈希的前後數據並沒有順序性,是採用散列的方式進行分佈,所以哈希雖好,但是根據業務系統開發的需要,我們更多采用的是B+tree的數據結構。

你可能又聽說過B-tree,那麼B-tree和B+tree又有什麼差異?下面從B+tree的演變歷史來說起

4,B+tree的演變歷史

4.1 演變路線圖

二叉樹---》平衡二叉樹---》B-tree---》B+tree

下面,我們以同樣存放進1-9的數據為例,來看他們有什麼差異

4.2 二叉樹

二叉樹,是每個節點最多有兩個子節點,是一種左中右的數據結構。

存放1-9之後的結構如下:

03-看透索引本質這一篇就夠了

這就是二叉樹可能會存在的問題,數據一邊倒,而這樣就發揮不了二叉樹搜索的優勢,於是就有了平衡二叉樹

4.3 平衡二叉樹

平衡二叉樹,它要求左右兩個子樹的高度差不能超過1,並且左右子樹都是一顆平衡二叉樹。

跟二叉樹的最大差別在於,會通過左旋轉右旋轉來保證整棵二叉樹的平衡。

那麼採用平衡二叉樹,存儲的數據結構如下:

03-看透索引本質這一篇就夠了

那麼平衡二叉樹,看著已經挺完美了,又有什麼問題?

隨著數據量的增加,這顆平衡二叉樹的深度也會遞增,而在索引樹進行查找時,隨著深度的遞增,跟IO交互的次數也會遞增,那麼性能也會下降,所以解決的辦法在哪?

沒錯,就是在一樣的數據量的情況下,減少數的深度。如何做到?

如果你想到了,真的很不錯,就是將平衡二叉樹變為多叉查找樹,這就是我們要講的B-tree

4.4 B-tree

採用B-tree結構,存儲的數據應該是這樣的,很明顯,層次變少了,這樣就減少了我們跟IO交互的次數

03-看透索引本質這一篇就夠了

但是,這就完美了嗎?

還是不夠,我們再來認識B-tree的升級版B+tree

4.5 B+tree

B+tree,也稱多路搜索樹,他們最大的區別是,B+tree所有的數據都保存在葉子節點上,節點按照大小進行排序,結構圖如下:

03-看透索引本質這一篇就夠了

4.6 結論

所以,最終MySQL採用的是B+tree的數據結構,看完以上的分析,你應該已經清晰知道索引是一種什麼樣的數據結構,為什麼可以提高搜索效率了。

4.7 衍生,聚集索引和非聚集索引

在MySQL裡面,還存在,一個聚集索引和非聚集索引,他們都是指B+tree的一種具體表現,那麼有什麼區別?

4.7.1 聚集索引

MySQL無法主動創建聚集索引,InnoDB存儲引擎會將我們的主鍵作為聚集索引。如果沒有定義主鍵,則InnoDB會選擇一個唯一的非空索引代替。如果沒有這樣的索引,則InnoDB會為該表生成一個rowid做為主鍵。

聚集索引的葉子節點存放表中所有的行數據信息,這樣找到索引就找到了數據,而不用繼續查詢,這就是為什麼以id主鍵查找數據,速度相比其他索引字段查找快的原因。

效果圖如下:(偷了懶,我只是畫了兩個作為代表)

03-看透索引本質這一篇就夠了

4.7.2 非聚集索引

我們創建的索引都屬於非聚集索引,葉子節點只存放自身的鍵值和主鍵的值,葉子節點並不包含所在行的數據記錄。

比如,我們為name創建了索引,那麼它就是非聚集索引。如果我們的查詢語句,是這樣

select name from sys_user where name='feng';

那麼,這個時候,使用的是覆蓋索引,即索引樹的數據就可以滿足我們的查詢需要。

而如果,這麼寫

select name,age,phone from sys_user where name='feng';

那麼,由於非聚集索引本身沒有包含行的數據,所以還需要根據自身保存的主鍵值,找到聚集索引樹,然後再得到行數據,所以這種情況下,相比直接按主鍵查找效率會低。

下面,給大家留兩個思考題:

1,索引的優點是提高查詢效率,那麼缺點是什麼?

2,UUID具有唯一性的特點,那麼是否合適作為主鍵?

希望對你有所幫助。

03-看透索引本質這一篇就夠了


分享到:


相關文章: