一祝蝠、索引
在之前,我對索引有以下的認知:
索引可以加快數(shù)據(jù)庫的檢索速度
表經(jīng)常進行INSERT/UPDATE/DELETE操作就不要建立索引了,換言之:索引會降低插入绎狭、刪除细溅、修改等維護任務(wù)的速度。
使用索引為什么可以加快數(shù)據(jù)庫的檢索速度袄芩弧喇聊?
為什么說索引會降低插入、刪除蹦狂、修改等維護任務(wù)的速度誓篱。
索引的最左匹配原則指的是什么?
Hash索引和B+樹索引有什么區(qū)別凯楔?主流的使用哪一個比較多窜骄?InnoDB存儲都支持嗎?
聚集索引和非聚集索引有什么區(qū)別啼辣?
........
1.1聊聊索引的基礎(chǔ)知識
首先Mysql的基本存儲結(jié)構(gòu)是頁(記錄都存在頁里邊):
各個數(shù)據(jù)頁之間可以組成一個雙向鏈表
而每個數(shù)據(jù)頁中的記錄又可以組成一個單向鏈表
每個數(shù)據(jù)頁都會為存儲在它里邊兒的記錄生成一個頁目錄啊研,在通過主鍵查找某條記錄的時候可以在頁目錄中使用二分法快速定位到對應(yīng)的槽御滩,然后再遍歷該槽對應(yīng)分組中的記錄即可快速找到指定的記錄
以其他列(非主鍵)作為搜索條件:只能從最小記錄開始依次遍歷單鏈表中的每條記錄鸥拧。
所以說,如果我們寫select * from user where username = 'Java3y'這樣沒有進行任何優(yōu)化的sql語句削解,默認會這樣做:
定位到記錄所在的頁
需要遍歷雙向鏈表富弦,找到所在的頁
從所在的頁內(nèi)中查找相應(yīng)的記錄
由于不是根據(jù)主鍵查詢,只能遍歷所在頁的單鏈表了
很明顯氛驮,在數(shù)據(jù)量很大的情況下這樣查找會很慢腕柜!
1.2索引提高檢索速度
索引做了些什么可以讓我們查詢加快速度呢?
其實就是將無序的數(shù)據(jù)變成有序(相對):
要找到id為8的記錄簡要步驟:
很明顯的是:沒有用索引我們是需要遍歷雙向鏈表來定位對應(yīng)的頁矫废,現(xiàn)在通過**“目錄”**就可以很快地定位到對應(yīng)的頁上了盏缤!
其實底層結(jié)構(gòu)就是B+樹,B+樹作為樹的一種實現(xiàn)蓖扑,能夠讓我們很快地查找出對應(yīng)的記錄唉铜。
參考資料:
1.3索引降低增刪改的速度
B+樹是平衡樹的一種。
平衡樹:它是一棵空樹或它的左右兩個子樹的高度差的絕對值不超過1律杠,并且左右兩個子樹都是一棵平衡二叉樹潭流。
如果一棵普通的樹在極端的情況下,是能退化成鏈表的(樹的優(yōu)點就不復(fù)存在了)
B+樹是平衡樹的一種柜去,是不會退化成鏈表的灰嫉,樹的高度都是相對比較低的(基本符合矮矮胖胖(均衡)的結(jié)構(gòu))【這樣一來我們檢索的時間復(fù)雜度就是O(logn)】!從上一節(jié)的圖我們也可以看見嗓奢,建立索引實際上就是建立一顆B+樹讼撒。
B+樹是一顆平衡樹,如果我們對這顆樹增刪改的話,那肯定會破壞它的原有結(jié)構(gòu)根盒。
要維持平衡樹瞻颂,就必須做額外的工作。正因為這些額外的工作開銷郑象,導(dǎo)致索引會降低增刪改的速度
B+樹刪除和修改具體可參考:
1.4哈希索引
除了B+樹之外贡这,還有一種常見的是哈希索引。
哈希索引就是采用一定的哈希算法厂榛,把鍵值換算成新的哈希值盖矫,檢索時不需要類似B+樹那樣從根節(jié)點到葉子節(jié)點逐級查找,只需一次哈希算法即可立刻定位到相應(yīng)的位置击奶,速度非潮菜快。本質(zhì)上就是把鍵值換算成新的哈希值柜砾,根據(jù)這個哈希值來定位湃望。
看起來哈希索引很牛逼啊,但其實哈希索引有好幾個局限(根據(jù)他本質(zhì)的原理可得):
哈希索引也沒辦法利用索引完成排序
不支持最左匹配原則
在有大量重復(fù)鍵值情況下痰驱,哈希索引的效率也是極低的---->哈希碰撞問題证芭。
不支持范圍查詢
參考資料:
www.cnblogs.com/zengkefu/p/…---hash索引和b+tree索引
1.5InnoDB支持哈希索引嗎?
主流的還是使用B+樹索引比較多担映,對于哈希索引废士,InnoDB是自適應(yīng)哈希索引的(hash索引的創(chuàng)建由InnoDB存儲引擎引擎自動優(yōu)化創(chuàng)建,我們干預(yù)不了)蝇完!
參考資料:
1.6聚集和非聚集索引
簡單概括:
聚集索引就是以主鍵創(chuàng)建的索引
非聚集索引就是以非主鍵創(chuàng)建的索引
區(qū)別:
聚集索引在葉子節(jié)點存儲的是表中的數(shù)據(jù)
非聚集索引在葉子節(jié)點存儲的是主鍵和索引列
使用非聚集索引查詢出數(shù)據(jù)時官硝,拿到葉子上的主鍵再去查到想要查找的數(shù)據(jù)。(拿到主鍵再查找這個過程叫做回表)
非聚集索引也叫做二級索引短蜕,不用糾結(jié)那么多名詞氢架,將其等價就行了~
非聚集索引在建立的時候也未必是單列的,可以多個列來創(chuàng)建索引朋魔。
此時就涉及到了哪個列會走索引岖研,哪個列不走索引的問題了(最左匹配原則-->后面有說)
創(chuàng)建多個單列(非聚集)索引的時候,會生成多個索引樹(所以過多創(chuàng)建索引會占用磁盤空間)
在創(chuàng)建多列索引中也涉及到了一種特殊的索引-->覆蓋索引
我們前面知道了铺厨,如果不是聚集索引缎玫,葉子節(jié)點存儲的是主鍵+列值
最終還是要“回表”,也就是要通過主鍵再查找一次解滓。這樣就會比較慢
覆蓋索引就是把要查詢出的列和索引是對應(yīng)的赃磨,不做回表操作!
比如說:
現(xiàn)在我創(chuàng)建了索引(username,age)洼裤,在查詢數(shù)據(jù)的時候:select username , age from user where username = 'Java3y' and age = 20邻辉。
很明顯地知道,我們上邊的查詢是走索引的,并且值骇,要查詢出的列在葉子節(jié)點都存在莹菱!所以,就不用回表了~
所以吱瘩,能使用覆蓋索引就盡量使用吧~
1.7索引最左匹配原則
最左匹配原則:
索引可以簡單如一個列(a)道伟,也可以復(fù)雜如多個列(a, b, c, d),即聯(lián)合索引使碾。
如果是聯(lián)合索引蜜徽,那么key也由多個列組成,同時票摇,索引只能用于查找key是否存在(相等)拘鞋,遇到范圍查詢(>、<矢门、between盆色、like左匹配)等就不能進一步匹配了,后續(xù)退化為線性查找祟剔。
因此隔躲,列的排列順序決定了可命中索引的列數(shù)。
例子:
如有索引(a, b, c, d)峡扩,查詢條件a = 1 and b = 2 and c > 3 and d = 4蹭越,則會在每個節(jié)點依次命中a、b教届、c,無法命中d驾霜。(很簡單:索引命中只能是相等的情況案训,不能是范圍匹配)
1.8=、in自動優(yōu)化順序
不需要考慮=粪糙、in等的順序强霎,mysql會自動優(yōu)化這些條件的順序,以匹配盡可能多的索引列蓉冈。
例子:
如有索引(a, b, c, d)城舞,查詢條件c > 3 and b = 2 and a = 1 and d < 4與a = 1 and c > 3 and b = 2 and d < 4等順序都是可以的,MySQL會自動優(yōu)化為a = 1 and b = 2 and c > 3 and d < 4寞酿,依次命中a家夺、b、c伐弹。
1.9索引總結(jié)
索引在數(shù)據(jù)庫中是一個非常重要的知識點拉馋!上面談的其實就是索引最基本的東西,要創(chuàng)建出好的索引要顧及到很多的方面:
1,最左前綴匹配原則煌茴。這是非常重要随闺、非常重要、非常重要(重要的事情說三遍)的原則蔓腐,MySQL會一直向右匹配直到遇到范圍查詢(>,<,BETWEEN,LIKE)就停止匹配矩乐。
3,盡量選擇區(qū)分度高的列作為索引回论,區(qū)分度的公式是COUNT(DISTINCT col) / COUNT(*)绰精。表示字段不重復(fù)的比率,比率越大我們掃描的記錄數(shù)就越少透葛。
4笨使,索引列不能參與計算,盡量保持列“干凈”僚害。比如硫椰,F(xiàn)ROM_UNIXTIME(create_time) = '2016-06-06'就不能使用索引,原因很簡單萨蚕,B+樹中存儲的都是數(shù)據(jù)表中的字段值靶草,但是進行檢索時,需要把所有元素都應(yīng)用函數(shù)才能比較岳遥,顯然這樣的代價太大奕翔。所以語句要寫成 :create_time = UNIX_TIMESTAMP('2016-06-06')。
5浩蓉,盡可能的擴展索引派继,不要新建立索引。比如表中已經(jīng)有了a的索引捻艳,現(xiàn)在要加(a,b)的索引驾窟,那么只需要修改原來的索引即可。
6认轨,單個多列組合索引和多個單列索引的檢索查詢效果不同绅络,因為在執(zhí)行SQL時,MySQL只能使用一個索引嘁字,會從多個單列索引中選擇一個限制最為嚴格的索引恩急。
參考資料:
zhuanlan.zhihu.com/p/23624390--簡單理解索引
blog.csdn.net/mysteryhaoh…--MySQL學習之——索引(普通索引、唯一索引纪蜒、全文索引衷恭、索引匹配原則、索引命中等)
monkeysayhi.github.io/2018/03/06/…---淺談MySQL的B樹索引與索引優(yōu)化
轉(zhuǎn)自:https://juejin.im/post/5b55b842f265da0f9e589e79