什么是回表查詢呢?
首先需要從InnoDB的索引實(shí)現(xiàn)說起,InnoDB有兩類索引:
1、聚集索引(clustered index)
2.、普通索引,也叫二級(jí)索引(secondary index)
聚集索引的葉子節(jié)點(diǎn)儲(chǔ)存的是行記錄,且每張表有且僅有一個(gè)聚集索引:
(1)、如果表中定義了主鍵,那么該主鍵索引就是聚集索引。
(2)、如果表中沒有定義主鍵,那么從第一個(gè)字段開始往后,第一個(gè) not null的unique列為聚集索引。
(3)、如果(1)、(2)都不滿足,那么InnoDB會(huì)創(chuàng)建一個(gè)隱藏的row-id作為聚集索引。
所以,主鍵查詢特別的快,直接定位到行記錄。
普通索引的葉子節(jié)點(diǎn)保存的是索引字段值和主鍵值,并不是完整的行記錄。
假設(shè)我們現(xiàn)在有一張表:
表結(jié)構(gòu)為 t (id PK , name KEY , sex , flag),其中id為聚集索引,name為普通索引。
表中有四條這樣的數(shù)據(jù):
(1, shenjian, m, A)、(3, zhangsan, m, A)、(5, lisi, m, A)、(9, wangwu, f, B )

上圖分別為它們?cè)谒饕械膬?chǔ)存狀態(tài):
(1)、聚集索引的葉子節(jié)點(diǎn)儲(chǔ)存了整個(gè)行記錄。
(2)、普通索引只儲(chǔ)存了name字段值和id值。
在假設(shè)現(xiàn)在有一條查詢sql select * from t where name = 'lisi';索引是怎么執(zhí)行的呢?

執(zhí)行路徑為上圖中標(biāo)紅的步驟:
????(1)、先通過普通索引定位到主鍵id=5。
????(2)、在通過聚集索引定位到對(duì)應(yīng)的行記錄。
需要先定位聚集索引值,在通過聚集索引定位到行記錄,這種現(xiàn)象就是
回表查詢。
那什么又是索引覆蓋呢?
mysql官方?jīng)]有對(duì)此進(jìn)行定義,但是有這方面的概述: 只需要通過一顆索引樹,就可以獲取sql所需要的列數(shù)據(jù),無需回表,速度更快。
仍舊選擇之前的表,但是我們的sql換成: select id,name from t where name = 'lisi';,查看explain計(jì)劃:

可以看到,命中了name索引,索引儲(chǔ)存了id和name,所以Extra項(xiàng)的值為Using index,無需回表查詢,符合索引覆蓋,效率高。
另外一條sql : select id,name,sex from t where name = 'lisi';,查看explain計(jì)劃:

可以看到,同樣的,也命中了name索引,但是索引的葉子節(jié)點(diǎn)并沒有儲(chǔ)存sex字段值,所以Extra項(xiàng)的值為Using index condition,需要回表查詢通過聚集索引獲取到sex的值,不符合索引覆蓋,效率相對(duì)較低。
解決的辦法是,將name索引修改為name、sex的組合索引,這樣第二條sql查詢就也滿足索引覆蓋的要求了。