如何避免回表


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";

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM