1.mysql索引優化實踐

索引的本質解析

慢查詢現象:一條sql原來執行幾十毫秒,現在卻執行了幾十秒甚至更長。
這種現象,最先想到的就是加索引.不要遇到問題就直接分庫分表,可能加索引就能搞定。
在這裏插入圖片描述
比如我有2列7行的一張表。如果要查找col2=89的數據,就是寫“select * from t where t.col2 = 89”,在沒有索引的情況下,會一行一行的比對,直到找到結果或者全部比對一遍之後找不到。因爲數據是存在磁盤上的,不做任何優化的話,全部比對一遍會引發大量的磁盤io。
如果像上圖一樣,使用二叉樹作爲索引,插入的時候,往二叉樹中插入,查詢的時候就能通過二叉樹快速的查找我們的元素。比如查找89,從根節點開始,如果大於根節點那就去右子樹查找,如果小於就去左子樹查找,重複這個過程直到找到。
每一個節點都是k-v鍵值對,k是值,比如89,77,value就是數據在磁盤上的位置(理解爲地址指針)。
總結:不加索引,逐行查找,加了索引,按照數據結構的特性去查找,大大減少查找遍歷次數,
注意:mysql的底層不是用的二叉樹。一般是b樹或者b+樹。因爲二叉樹在某些場景下有弊端。
推薦一個好的數據結構學習網站:
在這裏插入圖片描述
使用這個工具測試二叉樹作爲索引的弊端,假設我們的數據從1開始遞增。
在這裏插入圖片描述
如果數據單邊增長,二叉樹就變成鏈表了,失去了二叉樹的意義。鏈表的查找又變成從頭開始遍歷了,跟不加索引一個效果。

紅黑樹和B+樹畫圖解析

JDK裏面有個集合叫做hashmap,jdk1.8之後把之前的底層的鏈表實現優化爲了紅黑樹實現。
紅黑樹現象:只要單邊的元素多到2層就會幫你自動平衡一下,解決了傳統二叉樹對單邊增長的數據不友好的問題。如下圖:
在這裏插入圖片描述
紅黑樹的奧義在於這種自動的平衡,紅黑樹是升級版本的二叉樹,叫二叉平衡樹。
但是紅黑樹,也沒有被mysql選中作爲索引的數據結構實現,有些場景是不適合的。比如當數據量上來之後,比如500W,樹的高度會十分的高,如果查抄的元素位於底部的葉子節點,那麼經歷的磁盤io次數也會很多,查找的效率也很低。
總結:紅黑樹無法解決在數據量很大時樹的高度問題,高度高了查找效率就降低下來了。
希望高度越小越好,又想要大數據量,那麼可以考慮多叉樹(每個節點多幾個索引)。思路也很簡單,縱向有限制,高度不能太高,就橫向發力,增加叉的數量。

在這裏插入圖片描述
B樹的思想,一個節點有很多數據,不連續的就空出來指針指向子節點,一次性load一個巨型的節點,然後從內存中找到想找的元素或者該去哪個子節點的指針。這種比多次load數據效率要高。
但是,凡事都有個度,不能把所有數據都放進一個節點裏,能不能載入內存是個問題,時間也是問題,哪怕載入了,就又變成了鏈表索引了。從計算機組成原理的角度來講,一次磁盤io沒辦法取出來太大的元素。所以一個節點大小設置要適中,不能太大,也不能太小。mysql設置的節點大小是16k:
在這裏插入圖片描述
mysql不是選的b-樹,是對b-樹做了改造。得到了一種b+樹的數據結構。
在這裏插入圖片描述
非葉子節點都是冗餘索引,葉子節點包括所有的索引字段。冗餘索引爲了效率更高。
爲什麼只有葉子節點才存儲data?
因爲非葉子節點大小要適中,data挪走了之後,就能橫向存更多的索引了。
mysql主鍵:bigint。葉子節點大小是16k,一個索引是4b,可以放1170個索引,如果樹的高度是3,全部放滿了,則可以存放多少數據?
假設一個葉子節點有16個索引+data的組合。
公式:1170117016=21,902,400‬ 大於2kw。
也就是說2kw的數據,可以把樹的高度控制在3,效率還是十分可以的。這就可以解釋爲什麼幾千萬的表幾百毫秒就出結果了。經過2-3次的磁盤io就能找到結果。如果不加索引這個io次數會十分恐怖。

myisam存儲引擎索引實現解析

掃盲:數據庫,表,索引,表裏的數據都是在磁盤上的data文件夾!
在這裏插入圖片描述

在這裏插入圖片描述
存儲引擎是形容表的,不是數據庫!儘管數據庫有設置存儲引擎的選項,但是最終還是以表爲主。下圖爲圖形化工具的設置界面。
在這裏插入圖片描述

看一下建表的語句也可以證明:
在這裏插入圖片描述
在這裏插入圖片描述

以myisam存儲引擎的表爲例,磁盤上有三個文件:
在這裏插入圖片描述
frm:表的框架性質的信息存儲在這個文件。
myd:存儲的是數據行的記錄。
myi:表的索引所在的位置,i是index索引。
在這裏插入圖片描述
數據文件存在myd文件,索引存在myi文件這是myisam存儲引擎的特點。
b+樹的data域存儲的是磁盤的地址指針。
在這裏插入圖片描述

對於innodb存儲引擎的表,數據文件如下:只有2個。
在這裏插入圖片描述
ibd:數據文件跟索引文件的合併。data域不再是地址指針,而是該條記錄的所有數據。
在這裏插入圖片描述

innodb存儲引擎索引實現解析

在這裏插入圖片描述
innodb這種索引和數據放在一個文件中的形式,不用回表了,省去了這一步驟。
在這裏插入圖片描述
—掃盲—
聚集(聚簇索引)索引:innodb的主鍵索引,就可以認爲是一個聚集索引。葉節點包含了完整的數據記錄。
非聚集索引:myisam的主鍵索引就是非聚集索引。
聚集和非聚集可以理解爲指的是索引文件和數據文件是否是一個文件。
爲什麼innodb表必須要有主鍵,並且推薦使用整型自增的主鍵?
因爲設計如此,innodb的主鍵索引就是用b+樹來組織的(也是必須用b+樹)。所以必須要有主鍵。沒有主鍵數據就沒有一個結構去存儲。
如果你沒有建立主鍵,那麼mysql會自動選擇一個不重複的字段作爲innodb表的隱式主鍵。用這個字段來維護整個表裏的所有數據。
如果整張表裏的字段都選不到唯一的,那麼mysql會在後臺給你這張表生成一列唯一的數據。有點類似rowid字段。
爲什麼innodb的表主鍵推薦用整型自增?有的還是用uuid(非整型自增),這個有沒有什麼說法?
之所以是整型,是因爲load節點到內存中之後,需要不斷的比大小,整型的比較效率是很高的,比非整型(字符串)效率高,所以主鍵推薦用整型。字符串比較大小,需要轉換成ASCII碼來比對,效率很低(逐個字母比對)。從存儲空間上來講,整型也有更多的優勢,同樣空間可以存更多。

索引是怎麼支撐千萬級別表的快速查找

索引列推薦爲整型可以理解了,那麼爲什麼還要自增呢?
因爲b+樹相比較b樹,葉子節點之間還有指針的關聯,這是他倆的區別。
擴展一下:mysql表的索引除了有BTREE還有HASH。hash是每插入一次元素,就會對這個元素做一次hash運算,把運算的結果值存放到另一張hash表裏面,這個表裏面也有數據的磁盤地址,可以這麼理解:查找的時候對一行的某個值做一次hash運算,就能快速的找到這一行所在的磁盤文件地址,這就是hash索引。mysql底層實現了自己的hash散列算法。
hash算法比BTREEE方法快得多(上億的數據也很快,hash衝突mysql也解決的很好),爲什麼大部分還是用BTREE呢?
因爲他對範圍查找就無可奈何了,只能具體的查找where col = xxx的場景。但是where col > 6 就完蛋了。
B樹應對範圍查找也很乏力,但是B+樹就可以,就是因爲葉子節點有指針(雙向指針,圖不準確)的關聯,而且有遞增的趨勢。
在這裏插入圖片描述
上面提的都是單值索引,工作中用的比較多的還有聯合索引。那麼聯合索引的底層結構長啥樣?
如果能想明白,那麼按照原因去寫sql,會比單純的背一些sql優化方法要好很多。理解 = 不用背百分之80的索引優化原則。
在這裏插入圖片描述

mysql索引優化最佳實踐

在這裏插入圖片描述

聯合索引如上圖所示,先從左側開始匹配,如果第一個字段相同,就往後找。
聯合索引,必須加上第一個索引字段,只用後面的字段不觸發索引。查詢速度得不到提升。
在這裏插入圖片描述
結合一下最左前綴法則,可以從底層數據結構的角度理解聯合索引。
如何確定你的sql有沒有走索引?
在這裏插入圖片描述

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