索引條件下推(ICP)是對MySQL使用索引從表中檢索行的情況的優化。如果沒有ICP,存儲引擎會遍歷索引以查找基表中的行,並將它們返回給MySQL服務器,該服務器會評估WHERE行的條件。啟用ICP后,如果WHERE只使用索引中的列來評估部分 條件,MySQL服務器會推送這部分內容。WHERE條件下到存儲引擎。然后,存儲引擎通過使用索引條目來評估推送的索引條件,並且僅當滿足該條件時才從表中讀取行。ICP可以減少存儲引擎必須訪問基表的次數以及MySQL服務器必須訪問存儲引擎的次數。
指數條件下推優化的適用性受以下條件限制:
-
ICP用於 range, ref, eq_ref,和 ref_or_null訪問方法時,有必要訪問完整的表行。
-
ICP可用於表InnoDB 和MyISAM表,包括分區InnoDB和 MyISAM表。
-
對於InnoDB表,ICP僅用於二級索引。ICP的目標是減少全行讀取的數量,從而減少I / O操作。對於 InnoDB聚簇索引,已將完整記錄讀入InnoDB 緩沖區。在這種情況下使用ICP不會降低I / O.
-
在虛擬生成列上創建的二級索引不支持ICP。InnoDB 支持虛擬生成列上的二級索引。
-
引用子查詢的條件無法下推。
-
引用存儲函數的條件無法下推。存儲引擎無法調用存儲的函數。
-
觸發條件無法下推。(有關觸發條件的信息,請參見 第8.2.2.4節“使用EXISTS策略優化子查詢”。)
要了解此優化的工作原理,請首先考慮在不使用索引條件下推時索引掃描的進度:
獲取下一行,首先讀取索引元組,然后使用索引元組找到並讀取整個表行。
測試WHERE適用於此表的條件部分。根據測試結果接受或拒絕該行。
使用索引條件下推,掃描會像這樣進行:
獲取下一行的索引元組(但不是完整的表行)。
測試WHERE適用於此表的條件部分,並且只能使用索引列進行檢查。如果不滿足條件,則繼續下一行的索引元組。
如果滿足條件,請使用索引元組來查找並讀取整個表行。
測試WHERE 適用於此表的條件的剩余部分。根據測試結果接受或拒絕該行。
EXPLAIN使用“索引條件下推”時,輸出顯示 Using index condition在 Extra列中。它沒有顯示,Using index 因為當必須讀取完整的表行時,這不適用。
假設一個表包含有關人員及其地址的信息,並且該表的索引定義為 INDEX (zipcode, lastname, firstname)。如果我們知道一個人的zipcode價值但不確定姓氏,我們可以這樣搜索:
SELECT * FROM people
WHERE zipcode='95054'
AND lastname LIKE '%etrunia%'
AND address LIKE '%Main Street%';
MySQL可以使用索引來掃描人 zipcode='95054'。第二部分(lastname LIKE '%etrunia%')不能用於限制必須掃描的行數,因此,如果沒有Index Condition Pushdown,此查詢必須為所有擁有的人檢索完整的表行 zipcode='95054'。
使用索引條件下推,MySQL lastname LIKE '%etrunia%'在讀取整個表行之前檢查該 部分。這樣可以避免讀取與索引元組相對應的完整行,這些索引元組與zipcode條件匹配 但不符合 lastname條件。
默認情況下啟用索引條件下推。可以optimizer_switch通過設置index_condition_pushdown標志來控制 系統變量 :
SET optimizer_switch = 'index_condition_pushdown=off';
SET optimizer_switch = 'index_condition_pushdown=on';
總結
1.對於 where constant + like查詢可以嘗試使用聯合索引
// name和stu_id有聯合索引
explain select * from course where name = 'ww' and stu_id like '%4%';
2.對於 where constant + order by index column可以嘗試使用聯合索引;
// name和stu_id有聯合索引
explain select * from course where name = 'ww' order by stu_id;
以上另種情況都會使用Using index condition。第一種是過濾like的模糊匹配,第二種是進行聯合索引的排序。
索引下推經常使用的場景:
- 對於二級索引
- select的列不使用覆蓋索引
- 多條件查詢(where中多條件,where + order by) + 聯合索引