索引條件下推 (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';
請參閱 第 10.9.2 節「可切換的最佳化」。