索引條件下推 (ICP) 是一種最佳化,適用於 MySQL 使用索引從資料表擷取資料列的情況。在沒有 ICP 的情況下,儲存引擎會遍歷索引以找到基底資料表中的資料列,並將它們傳回 MySQL 伺服器,後者會評估資料列的 WHERE
條件。啟用 ICP 後,如果 WHERE
條件的部分可以使用索引中的資料行來評估,則 MySQL 伺服器會將 WHERE
條件的這部分下推到儲存引擎。然後,儲存引擎會使用索引條目評估下推的索引條件,並且僅在滿足此條件時才從資料表中讀取資料列。ICP 可以減少儲存引擎必須存取基底資料表的次數,以及 MySQL 伺服器必須存取儲存引擎的次數。
索引條件下推最佳化的適用性受限於以下條件
當需要存取完整的資料表資料列時,ICP 用於
range
、ref
、eq_ref
和ref_or_null
存取方法。對於
InnoDB
資料表,ICP 僅用於輔助索引。ICP 的目標是減少完整資料列的讀取次數,進而減少 I/O 操作。對於InnoDB
叢集索引,完整的記錄已經讀入InnoDB
緩衝區。在這種情況下使用 ICP 並不會減少 I/O。在虛擬產生欄位上建立的輔助索引不支援 ICP。
InnoDB
支援虛擬產生欄位上的輔助索引。參考子查詢的條件無法下推。
參考儲存函數的條件無法下推。儲存引擎無法調用儲存函數。
觸發條件無法下推。(有關觸發條件的資訊,請參閱第 10.2.2.3 節「使用 EXISTS 策略最佳化子查詢」。)
條件無法下推至包含系統變數參考的衍生資料表。
若要了解此最佳化如何運作,請先考慮當未使用索引條件下推時,索引掃描如何進行
取得下一列,首先讀取索引元組,然後使用索引元組定位並讀取完整資料表列。
測試適用於此資料表的
WHERE
條件部分。根據測試結果接受或拒絕該列。
使用索引條件下推,掃描會改為這樣進行
取得下一列的索引元組(但不是完整資料表列)。
測試適用於此資料表且僅可使用索引欄位檢查的
WHERE
條件部分。如果條件不滿足,則繼續處理下一列的索引元組。如果條件滿足,則使用索引元組定位並讀取完整資料表列。
測試適用於此資料表的
WHERE
條件的其餘部分。根據測試結果接受或拒絕該列。
當使用索引條件下推時,EXPLAIN
輸出會在 Extra
欄位中顯示 Using index condition
。它不會顯示 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%'
) 無法用於限制必須掃描的資料列數量,因此如果沒有索引條件下推,此查詢必須檢索所有 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';