01 回表
在使用非聚簇索引查詢數據時,根據主鍵ID到聚簇索引上查詢數據的過程稱為回表。有關聚簇與非聚簇索引以及回表的過程可以點擊下圖查看相關文章

02 覆蓋索引
先來看看MySQL官方對EXPLIAN工具的輸出字段Extra infomation中有關覆蓋索引的描述

鏈接地址:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html#explain-extra-information
切換一下語言,核心觀點為:
-
Using index
無需回表,查詢需要返回的列信息直接從索引樹獲得,不再訪問物理行數據
-
Using index condition
需要回表,存儲引擎層根據索引盡可能的過濾數據,然后在返回給服務器層根據WHERE其他條件進行過濾(索引下推)
-
覆蓋索引必定是非聚簇索引,事實上聚簇索引不需要回表
一個例子
CREATE TABLE t( id INT PRIMARY KEY, c1 VARCHAR(32), c2 VARCHAR(8), INDEX(c1) )ENGINE=innodb;
第一個SQL
能命中索引c1,並從c1的索引樹中直接獲得id、c1,無需回表

第二個SQL
能命中索引c1,但c1的索引樹中不存在c2列,需要回表
將單列索引index(c1)更改為聯合索引index(c1,c2),從下圖的執行計划看到,已經都不需要回表了。
ALTER TABLE t DROP INDEX c1; ALTER TABLE t ADD INDEX c1_c2(c1,c2);

03 索引下推
索引下推(Index Condition Pushdown,簡稱ICP),是MySQL5.6版本的新特性,它能減少回表查詢次數,提高查詢效率。

MySQL服務層負責SQL語法解析、生成執行計划等,並調用存儲引擎層執行數據的存儲和檢索。索引下推是指將部分上層(服務層)負責的事情(如WHERE查詢),交給了下層(引擎層)去處理。
無ICP查詢過程
- 存儲引擎讀取索引;
- 根據索引中的主鍵值,定位並讀取完整的行記錄(回表);
- 存儲引擎把記錄交給服務層去檢測該記錄是否滿足WHERE條件。
ICP查詢過程
- 存儲引擎讀取索引;
- 判斷WHERE條件部分能否用索引中的列來做檢查
1. 條件不滿足,處理下一行記錄(丟棄,減少回表次數);
2. 條件滿足,用索引中的主鍵去定位並讀取完整的行記錄(回表);
- 存儲引擎把記錄交給服務層,服務層檢測該記錄是否滿足WHERE條件的其余部分。
04 索引下推實踐
CREATE TABLE t( id INT PRIMARY KEY, name VARCHAR(64), age INT, sex INT, INDEX(name,age) )ENGINE=innodb;
創建一張表t,建立聯合索引(name, age),並寫入下面數據:

需求:查詢所有name以'蕭'開頭且age等9的記錄
SELECT * FROM t WHERE name LIKE '蕭%' AND age=9;
無ICP查詢過程

由於索引的左匹配原則,只能使用name,無法使用age。通過name分別找到匹配的主鍵1、2,然后回表查詢取出記錄,最后交由服務層進行WHERE判斷,回表2次。
ICP查詢過程

可以看到在引擎層篩選掉了不符合age條件的記錄,只需要回表一次。
ICP開啟狀態查詢
SHOW VARIABLES LIKE '%optimizer_switch%';
狀態開啟與關閉
SET optimizer_switch="index_condition_pushdown=off/on";
