互聯(lián)網(wǎng)大廠面試:在MySQL中使用!=還能走索引嗎?
一般情況下,我們會(huì)在一個(gè)索引上較多的使用等值查詢(xún)或者范圍查詢(xún),此時(shí)索引大多可以幫助我們極快的查詢(xún)出我們需要的數(shù)據(jù)。
那當(dāng)我們?cè)趙here條件中對(duì)索引列使用!=查詢(xún),索引還能發(fā)揮他的作用嗎?
以此SQL為例:
MySQL會(huì)如何執(zhí)行這個(gè)SQL呢?是直接全表掃描嗎?
其實(shí),走不走索引,只取決于一個(gè)因素,那就是成本。
我們知道,MySQL中有一個(gè)叫做優(yōu)化器的東西,他會(huì)對(duì)每一條查詢(xún)sql做成本分析,然后根據(jù)分析結(jié)果選擇是否使用索引或者全表掃描。
對(duì)于上面的sql,優(yōu)化器會(huì)將k!=6轉(zhuǎn)化為兩個(gè)區(qū)間查詢(xún)(-∞,6)和(6,+∞),然后對(duì)索引樹(shù)進(jìn)行成本計(jì)算。
我們畫(huà)一個(gè)簡(jiǎn)略版的二級(jí)索引樹(shù)。
簡(jiǎn)單解釋一下:每個(gè)顏色代表一個(gè)數(shù)據(jù)頁(yè)(MySQL與磁盤(pán)交互是以頁(yè)為單位,默認(rèn)一個(gè)頁(yè)是16kb,這里我們假設(shè)一個(gè)頁(yè)存兩條數(shù)據(jù),并且MySQL規(guī)定頁(yè)中的數(shù)據(jù)會(huì)有序排放并組成一個(gè)單向鏈表)。
對(duì)于一個(gè)普通的二級(jí)索引,葉子節(jié)點(diǎn)存儲(chǔ)是索引列和主鍵值,非葉子節(jié)點(diǎn)頁(yè)存儲(chǔ)是下方葉子節(jié)點(diǎn)的最小值和對(duì)應(yīng)的頁(yè)地址。(葉子節(jié)點(diǎn)是有序的,對(duì)應(yīng)的主鍵可不一定)
那么對(duì)于兩個(gè)區(qū)間查詢(xún)(-∞,6)和(6,+∞)意味著什么呢?
如果一個(gè)二級(jí)索引樹(shù)的數(shù)據(jù)簡(jiǎn)化為12條數(shù)據(jù),那么就有1-5,7-12共計(jì)11條數(shù)據(jù)要被掃描,然后進(jìn)行11次回表。
也就是說(shuō),如果表中有120萬(wàn)條數(shù)據(jù),要回表110萬(wàn)次。
emm,MySQL一看這么麻煩,還掃描什么二級(jí)索引樹(shù)啊,直接全表掃描走起吧。
那難道說(shuō),對(duì)于!=查詢(xún)就用不了索引了嗎?
非也。
如果數(shù)據(jù)集是下面這種,情況可能就不一樣了。
在這個(gè)索引樹(shù)上,索引值為6的占據(jù)了很大一部分,那么MySQL掃描成本就會(huì)大大降低了。
此時(shí)掃描的行數(shù)變成了1,10-12,共計(jì)3行。
相對(duì)于全表掃描,此時(shí)走二級(jí)索引樹(shù)掃描,顯然代價(jià)是比較低的。
也就是說(shuō),對(duì)于!=是否可以使用索引,要看具體的場(chǎng)景。
總結(jié)一下就是,MySQL判斷某個(gè)sql是否走索引,其實(shí)取決于成本分析。
如果使用二級(jí)索引的成本更低,MySQL就會(huì)傾向于使用二級(jí)索引。
如果使用二級(jí)索引掃描的行數(shù)占比過(guò)高,導(dǎo)致需要頻繁的回表,MySQL經(jīng)過(guò)計(jì)算之后覺(jué)得走二級(jí)索引的代價(jià)太大了,就會(huì)使用全表掃描。