本文來自一位不愿意透露姓名的粉絲投稿
相信很多人對于MySQL的索引都不陌生,索引(Index)是幫助MySQL高效獲取數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu)弦追。
因為索引是MySQL中比較重點的知識,相信很多人都有一定的了解湘捎,尤其是在面試中出現(xiàn)的頻率特別高近哟。樓主自認(rèn)為自己對MySQL的索引相關(guān)知識有很多了解胎源,而且因為最近在找工作面試译株,所以單獨復(fù)習(xí)了很多關(guān)于索引的知識瓜喇。
但是,我還是圖樣圖森破歉糜,直到我被阿里的面試官虐過之后我才知道乘寒,自己在索引方面的知識,只是個小學(xué)生水平匪补。
以下伞辛,是我總結(jié)的一次阿里面試中關(guān)于索引有關(guān)的問題以及知識點。
索引概念夯缺、索引模型
我們是怎么聊到索引的呢蚤氏,是因為我提到我們的業(yè)務(wù)量比較大,每天大概有幾百萬的新數(shù)據(jù)生成踊兜,于是有了以下對話:
面試官:你們每天這么大的數(shù)據(jù)量竿滨,都是保存在關(guān)系型數(shù)據(jù)庫中嗎?
我:是的捏境,我們線上使用的是MySQL數(shù)據(jù)庫
面試官:每天幾百萬數(shù)據(jù)于游,一個月就是幾千萬了,那你們有沒有對于查詢做一些優(yōu)化呢垫言?
我:我們在數(shù)據(jù)庫中創(chuàng)建了一些索引(我現(xiàn)在非常后悔我當(dāng)時說了這句話)贰剥。
這里可以看到,阿里的面試官并不會像有一些公司一樣拿著題庫一道一道的問骏掀,而是會根據(jù)面試者做過的事情以及面試過程中的一些內(nèi)容進行展開鸠澈。
面試官:那你能說說什么是索引嗎柱告?
我:(這道題肯定難不住我敖赝浴)索引其實是一種數(shù)據(jù)結(jié)構(gòu),能夠幫助我們快速的檢索數(shù)據(jù)庫中的數(shù)據(jù)际度。
面試官:那么索引具體采用的哪種數(shù)據(jù)結(jié)構(gòu)呢葵袭?
我:(這道題我也背過)常見的MySQL主要有兩種結(jié)構(gòu):Hash索引和B+ Tree索引,我們使用的是InnoDB引擎乖菱,默認(rèn)的是B+樹坡锡。
這里我耍了一個小心機,特意說了一下索引和存儲引擎有關(guān)窒所。希望面試官可以問我一些關(guān)于存儲引擎的問題鹉勒。
面試官:既然你提到InnoDB使用的B+ Tree的索引模型,那么你知道為什么采用B+ 樹嗎吵取?這和Hash索引比較起來有什么優(yōu)缺點嗎禽额?
我:(突然覺得這道題有點難,但是我還是憑借著自己的知識儲備簡單的回答上一些)因為Hash索引底層是哈希表,哈希表是一種以key-value存儲數(shù)據(jù)的結(jié)構(gòu)脯倒,所以多個數(shù)據(jù)在存儲關(guān)系上是完全沒有任何順序關(guān)系的实辑,所以,對于區(qū)間查詢是無法直接通過索引查詢的藻丢,就需要全表掃描剪撬。所以,哈希索引只適用于等值查詢的場景悠反。而B+ Tree是一種多路平衡查詢樹残黑,所以他的節(jié)點是天然有序的(左子節(jié)點小于父節(jié)點、父節(jié)點小于右子節(jié)點)斋否,所以對于范圍查詢的時候不需要做全表掃描萍摊。
面試官:除了上面這個范圍查詢的,你還能說出其他的一些區(qū)別嗎如叼?
我:(這個題我回答的不好冰木,事后百度了一下)
科普時間:B+ Tree索引和Hash索引區(qū)別 哈希索引適合等值查詢,但是不無法進行范圍查詢 哈希索引沒辦法利用索引完成排序 哈希索引不支持多列聯(lián)合索引的最左匹配規(guī)則 如果有大量重復(fù)鍵值得情況下笼恰,哈希索引的效率會很低踊沸,因為存在哈希碰撞問題
聚簇索引、覆蓋索引
面試官:剛剛我們聊到B+ Tree 社证,那你知道B+ Tree的葉子節(jié)點都可以存哪些東西嗎逼龟?
我:InnoDB的B+ Tree可能存儲的是整行數(shù)據(jù),也有可能是主鍵的值追葡。
面試官:那這兩者有什么區(qū)別嗎腺律? 我:(當(dāng)他問我葉子節(jié)點的時候,其實我就猜到他可能要問我聚簇索引和非聚簇索引了)在 InnoDB 里宜肉,索引B+ Tree的葉子節(jié)點存儲了整行數(shù)據(jù)的是主鍵索引匀钧,也被稱之為聚簇索引。而索引B+ Tree的葉子節(jié)點存儲了主鍵的值的是非主鍵索引谬返,也被稱之為非聚簇索引之斯。
面試官:那么,聚簇索引和非聚簇索引遣铝,在查詢數(shù)據(jù)的時候有區(qū)別嗎佑刷?
我:聚簇索引查詢會更快?
面試官:為什么呢酿炸?
我:因為主鍵索引樹的葉子節(jié)點直接就是我們要查詢的整行數(shù)據(jù)了瘫絮。而非主鍵索引的葉子節(jié)點是主鍵的值,查到主鍵的值以后填硕,還需要再通過主鍵的值再進行一次查詢麦萤。
面試官:剛剛你提到主鍵索引查詢只會查一次,而非主鍵索引需要回表查詢多次。(后來我才知道频鉴,原來這個過程叫做回表)是所有情況都是這樣的嗎栓辜?非主鍵索引一定會查詢多次嗎?
我:(額垛孔、這個問題我回答的不好藕甩,后來我自己查資料才知道,通過覆蓋索引也可以只查詢一次)
科普時間——覆蓋索引 覆蓋索引(covering index)指一個查詢語句的執(zhí)行只用從索引中就能夠取得周荐,不必從數(shù)據(jù)表中讀取狭莱。也可以稱之為實現(xiàn)了索引覆蓋。 當(dāng)一條查詢語句符合覆蓋索引條件時概作,MySQL只需要通過索引就可以返回查詢所需要的數(shù)據(jù)腋妙,這樣避免了查到索引后再返回表操作,減少I/O提高效率讯榕。 如骤素,表covering_index_sample中有一個普通索引 idx_key1_key2(key1,key2)。當(dāng)我們通過SQL語句:select key2 from covering_index_sample where key1 = ‘keytest’;的時候愚屁,就可以通過覆蓋索引查詢济竹,無需回表。
聯(lián)合索引霎槐、最左前綴匹配
面試官:不知道的話沒關(guān)系送浊,想問一下,你們在創(chuàng)建索引的時候都會考慮哪些因素呢丘跌?
我:我們一般對于查詢概率比較高袭景,經(jīng)常作為where條件的字段設(shè)置索引
面試官:那你們有用過聯(lián)合索引嗎?
我:用過呀闭树,我們有對一些表中創(chuàng)建過聯(lián)合索引耸棒。
面試官:那你們在創(chuàng)建聯(lián)合索引的時候,需要做聯(lián)合索引多個字段之間順序你們是如何選擇的呢蔼啦?
我:我們把識別度最高的字段放到最前面榆纽。
面試官:為什么這么做呢?
我:(這個問題有點把我問蒙了捏肢,稍微有些慌亂)這樣的話可能命中率會高一點吧。饥侵。鸵赫。
面試官:那你知道最左前綴匹配嗎?
我:(我突然想起來原來面試官是想問這個躏升,怪自己剛剛為什么就沒想到這個呢辩棒。)哦哦哦。您剛剛問的是這個意思啊,在創(chuàng)建多列索引時一睁,我們根據(jù)業(yè)務(wù)需求钻弄,where子句中使用最頻繁的一列放在最左邊,因為MySQL索引查詢會遵循最左前綴匹配的原則者吁,即最左優(yōu)先窘俺,在檢索數(shù)據(jù)時從聯(lián)合索引的最左邊開始匹配。所以當(dāng)我們創(chuàng)建一個聯(lián)合索引的時候复凳,如(key1,key2,key3)瘤泪,相當(dāng)于創(chuàng)建了(key1)、(key1,key2)和(key1,key2,key3)三個索引育八,這就是最左匹配原則对途。
雖然我一開始有點懵,沒有聯(lián)想到最左前綴匹配髓棋,但是面試官還是引導(dǎo)了我实檀。很友善。
索引下推按声、查詢優(yōu)化
面試官:你們線上用的MySQL是哪個版本啊呢劲妙?
我:我們MySQL是5.7
面試官:那你知道在MySQL 5.6中,對索引做了哪些優(yōu)化嗎儒喊?
我:不好意思镣奋,這個我沒有去了解過。(事后我查了一下怀愧,有一個比較重要的 :Index Condition Pushdown Optimization)
科普時間—— Index Condition Pushdown(索引下推) MySQL 5.6引入了索引下推優(yōu)化侨颈,默認(rèn)開啟,使用SET optimizer_switch = ‘index_condition_pushdown=off’;可以將其關(guān)閉芯义。官方文檔中給的例子和解釋如下: people表中(zipcode哈垢,lastname,firstname)構(gòu)成一個索引
SELECT * FROM people WHERE zipcode=‘95054’ AND lastname LIKE ‘%etrunia%’ AND address LIKE ‘%Main Street%’;
如果沒有使用索引下推技術(shù)扛拨,則MySQL會通過zipcode='95054’從存儲引擎中查詢對應(yīng)的數(shù)據(jù)耘分,返回到MySQL服務(wù)端,然后MySQL服務(wù)端基于lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來判斷數(shù)據(jù)是否符合條件绑警。 如果使用了索引下推技術(shù)求泰,則MYSQL首先會返回符合zipcode='95054’的索引,然后根據(jù)lastname LIKE '%etrunia%'和address LIKE '%Main Street%'來判斷索引是否符合條件计盒。如果符合條件渴频,則根據(jù)該索引來定位對應(yīng)的數(shù)據(jù),如果不符合北启,則直接reject掉卜朗。 有了索引下推優(yōu)化拔第,可以在有l(wèi)ike條件查詢的情況下,減少回表次數(shù)场钉。
面試官:你們創(chuàng)建的那么多索引蚊俺,到底有沒有生效,或者說你們的SQL語句有沒有使用索引查詢你們有統(tǒng)計過嗎逛万?
我:這個還沒有統(tǒng)計過泳猬,除非遇到慢SQL的時候我們才會去排查
面試官:那排查的時候,有什么手段可以知道有沒有走索引查詢呢泣港?
我:可以通過explain查看sql語句的執(zhí)行計劃暂殖,通過執(zhí)行計劃來分析索引使用情況
面試官:那什么情況下會發(fā)生明明創(chuàng)建了索引,但是執(zhí)行的時候并沒有通過索引呢当纱?
我:(依稀記得和優(yōu)化器有關(guān)呛每,但是這個問題并沒有回答好)
科普時間——查詢優(yōu)化器 一條SQL語句的查詢,可以有不同的執(zhí)行方案坡氯,至于最終選擇哪種方案晨横,需要通過優(yōu)化器進行選擇,選擇執(zhí)行成本最低的方案箫柳。 在一條單表查詢語句真正執(zhí)行之前手形,MySQL的查詢優(yōu)化器會找出執(zhí)行該語句所有可能使用的方案,對比之后找出成本最低的方案悯恍。這個成本最低的方案就是所謂的執(zhí)行計劃库糠。 優(yōu)化過程大致如下: 1、根據(jù)搜索條件涮毫,找出所有可能使用的索引 2瞬欧、計算全表掃描的代價 3、計算使用不同索引執(zhí)行查詢的代價 4罢防、對比各種執(zhí)行方案的代價艘虎,找出成本最低的那一個
面試官:哦,索引有關(guān)的知識我們暫時就問這么多吧咒吐。你們線上數(shù)據(jù)的事務(wù)隔離級別是什么呀野建?
我:(后面關(guān)于事務(wù)隔離級別的問題了,就不展開了)
感覺是因為我回答的不夠好恬叹,如果這幾個索引問題我都會的話候生,他還會追問更多,恐怕會被虐的更慘
總結(jié)&感悟
以上妄呕,就是一次面試中關(guān)于索引部分知識的問題以及我整理的答案陶舞。感覺這次面試過程中關(guān)于索引的知識,自己大概能夠回答的內(nèi)容占70%左右绪励,但是自信完全答對的內(nèi)容只占50%左右肿孵,看來自己索引有關(guān)的知識了解的還是不夠多。
通過這次面試疏魏,發(fā)現(xiàn)像阿里這種大廠對于底層知識還是比較看重的停做,我以前以為關(guān)于索引最多也就問一下Hash和B+有什么區(qū)別,沒想到最后都能問到查詢優(yōu)化器上面大莫。
最后蛉腌,不管本次面試能不能通過,都非常感謝有這樣一次機會只厘,可以讓自己看到自己的不足烙丛。通過這次面試,我也收獲了很多東西羔味。加油河咽!
原文鏈接:https://blog.csdn.net/hollis_chuang/article/details/95167242