const:
????通過主鍵列來定位一條記錄?例如:SELECT * FROM single_table WHERE id = 1438;
ref
? ??某個普通的二級索引列與常數(shù)進行等值比較??SELECT * FROM single_table WHERE key1 = 'abc';
ref_or_null
????找出某個二級索引列的值等于某個常數(shù)的記錄楞抡,還想把該列的值為NULL的記錄也找出來
? ??SELECT * FROM single_demo WHERE key1 = 'abc' OR key1 IS NULL;
range
????利用索引進行范圍匹配的訪問方法稱之為:range
????SELECT * FROM single_table WHERE key2 IN (1438, 6328) OR (key2 >= 38 AND key2 <= 79);
index????
? ? 聯(lián)合索引?查詢第一個字段時?使用index
? ??SELECT key_part1, key_part2, key_part3 FROM single_table WHERE key_part2 = 'abc';
all?
? ??最直接的查詢執(zhí)行方式就是我們已經(jīng)提了無數(shù)遍的全表掃描,對于InnoDB表來說也就是直接掃描聚簇索引纳像,設計MySQL的大叔把這種使用全表掃描執(zhí)行查詢的方式稱之為:all
二級索引 + 回表
一般情況下只能利用單個二級索引執(zhí)行查詢果覆,比方說下邊的這個查詢:
SELECT * FROM single_table WHERE key1 ='abc'AND key2 > 1000;
查詢優(yōu)化器會識別到這個查詢中的兩個搜索條件:
key1 = 'abc'
key2 > 1000
優(yōu)化器一般會根據(jù)single_table表的統(tǒng)計數(shù)據(jù)來判斷到底使用哪個條件到對應的二級索引中查詢掃描的行數(shù)會更少辐烂,選擇那個掃描行數(shù)較少的條件到對應的二級索引中查詢(關于如何比較的細節(jié)我們后邊的章節(jié)中會嘮叨)。然后將從該二級索引中查詢到的結果經(jīng)過回表得到完整的用戶記錄后再根據(jù)其余的WHERE條件過濾記錄拯爽。一般來說最蕾,等值查找比范圍查找需要掃描的行數(shù)更少(也就是ref的訪問方法一般比range好炕横,但這也不總是一定的源内,也可能采用ref訪問方法的那個索引列的值為特定值的行數(shù)特別多),所以這里假設優(yōu)化器決定使用idx_key1索引進行查詢份殿,那么整個查詢過程可以分為兩個步驟:
步驟1:使用二級索引定位記錄的階段膜钓,也就是根據(jù)條件key1 = 'abc'從idx_key1索引代表的B+樹中找到對應的二級索引記錄。
步驟2:回表階段卿嘲,也就是根據(jù)上一步驟中找到的記錄的主鍵值進行回表操作颂斜,也就是到聚簇索引中找到對應的完整的用戶記錄,再根據(jù)條件key2 > 1000到完整的用戶記錄繼續(xù)過濾拾枣。將最終符合過濾條件的記錄返回給用戶沃疮。
這里需要特別提醒大家的一點是,因為二級索引的節(jié)點中的記錄只包含索引列和主鍵梅肤,所以在步驟1中使用idx_key1索引進行查詢時只會用到與key1列有關的搜索條件司蔬,其余條件,比如key2 > 1000這個條件在步驟1中是用不到的凭语,只有在步驟2完成回表操作后才能繼續(xù)針對完整的用戶記錄中繼續(xù)過濾葱她。
明確range訪問方法使用的范圍區(qū)間
其實對于B+樹索引來說,只要索引列和常數(shù)使用=似扔、<=>、IN搓谆、NOT IN炒辉、IS NULL、IS NOT NULL泉手、>黔寇、<、>=斩萌、<=缝裤、BETWEEN屏轰、!=(不等于也可以寫成<>)或者LIKE操作符連接起來,就可以產生一個所謂的區(qū)間憋飞。
小貼士: LIKE操作符比較特殊霎苗,只有在匹配完整字符串或者匹配字符串前綴時才可以利用索引,具體原因我們在前邊的章節(jié)中嘮叨過了榛做,這里就不贅述了唁盏。 IN操作符的效果和若干個等值匹配操作符`=`之間用`OR`連接起來是一樣的,也就是說會產生多個單點區(qū)間检眯,比如下邊這兩個語句的效果是一樣的: SELECT * FROM single_table WHERE key2 IN (1438, 6328); SELECT * FROM single_table WHERE key2 = 1438 OR key2 = 6328;
不過在日常的工作中厘擂,一個查詢的WHERE子句可能有很多個小的搜索條件,這些搜索條件需要使用AND或者OR操作符連接起來
索引合并
我們前邊說過MySQL在一般情況下執(zhí)行一個查詢時最多只會用到單個二級索引锰瘸,但不是還有特殊情況么刽严,在這些特殊情況下也可能在一個查詢中使用到多個二級索引,設計MySQL的大叔把這種使用到多個索引來完成一次查詢的執(zhí)行方法稱之為:index merge避凝,具體的索引合并算法有下邊三種舞萄。
Intersection合并
Intersection翻譯過來的意思是交集。這里是說某個查詢可以使用多個二級索引恕曲,將從多個二級索引中查詢到的結果取交集鹏氧,比方說下邊這個查詢:
SELECT * FROM single_table WHERE key1 ='a'AND key3 ='b';
假設這個查詢使用Intersection合并的方式執(zhí)行的話,那這個過程就是這樣的:
從idx_key1二級索引對應的B+樹中取出key1 = 'a'的相關記錄佩谣。
從idx_key3二級索引對應的B+樹中取出key3 = 'b'的相關記錄把还。
二級索引的記錄都是由索引列 + 主鍵構成的,所以我們可以計算出這兩個結果集中id值的交集茸俭。
按照上一步生成的id值列表進行回表操作吊履,也就是從聚簇索引中把指定id值的完整用戶記錄取出來,返回給用戶调鬓。
這里有同學會思考:為啥不直接使用idx_key1或者idx_key3只根據(jù)某個搜索條件去讀取一個二級索引艇炎,然后回表后再過濾另外一個搜索條件呢?這里要分析一下兩種查詢執(zhí)行方式之間需要的成本代價腾窝。
只讀取一個二級索引的成本:
按照某個搜索條件讀取一個二級索引
根據(jù)從該二級索引得到的主鍵值進行回表操作缀踪,然后再過濾其他的搜索條件
讀取多個二級索引之后取交集成本:
按照不同的搜索條件分別讀取不同的二級索引
將從多個二級索引得到的主鍵值取交集,然后進行回表操作
雖然讀取多個二級索引比讀取一個二級索引消耗性能虹脯,但是讀取二級索引的操作是順序I/O驴娃,而回表操作是隨機I/O抄课,所以如果只讀取一個二級索引時需要回表的記錄數(shù)特別多扮休,而讀取多個二級索引之后取交集的記錄數(shù)非常少,當節(jié)省的因為回表而造成的性能損耗比訪問多個二級索引帶來的性能損耗更高時启昧,讀取多個二級索引后取交集比只讀取一個二級索引的成本更低。
Union合并
我們在寫查詢語句時經(jīng)常想把既符合某個搜索條件的記錄取出來疆柔,也把符合另外的某個搜索條件的記錄取出來咒精,我們說這些不同的搜索條件之間是OR關系。有時候OR關系的不同搜索條件會使用到不同的索引旷档,比方說這樣:
SELECT * FROM single_table WHERE key1 ='a'OR key3 ='b'
Intersection是交集的意思模叙,這適用于使用不同索引的搜索條件之間使用AND連接起來的情況;Union是并集的意思彬犯,適用于使用不同索引的搜索條件之間使用OR連接起來的情況向楼。與Intersection索引合并類似,MySQL在某些特定的情況下才可能會使用到Union索引合并:
情況一:二級索引列是等值匹配的情況谐区,對于聯(lián)合索引來說湖蜕,在聯(lián)合索引中的每個列都必須等值匹配,不能出現(xiàn)只出現(xiàn)匹配部分列的情況宋列。