MySQL查詢優化之索引條件下推
原文地址:https://dev.mysql.com/doc/refman/5.7/en/index-condition-pushdown-optimization.html
譯文:
8.2.1.5 索引條件下推優化
索引條件下推(ICP)是當MySQL使用索引從表中檢索行時使用的一種優化。如果沒有ICP,儲存引擎將遍歷索引以定位基表中的行,並將它們返回到MySQL伺服器,該伺服器將計算基錶行的where條件。在啟用ICP的情況下,如果部分where條件可以通過只使用索引中的列來計算,MySQL伺服器會把where條件的這部分推入儲存引擎。然後,儲存引擎通過使用索引條目來評估所推送的索引條件,並且只有在滿足該條件時才從表中讀取行。ICP可以減少儲存引擎必須訪問基本表的次數和MySQL伺服器必須訪問儲存引擎的次數。
索引條件下推優化的適用性取決於這些條件:
1)當需要訪問全錶行時,ICP用於range、ref、eq_ref和ref_or_null訪問方法;
2)ICP可以用於InnoDB表和MyISAM表,包括分割槽的InnoDB表和MyISAM表;
3)對InnoDB表來說,ICP只用於二級索引。ICP的目標是減少全行讀取的數量,從而減少I/O操作。對於InnoDB叢集索引,完整的記錄已經讀入InnoDB緩衝區。在這種情況下使用ICP並不會減少I/O;
4)在虛擬生成的列上建立的二級索引不支援ICP。InnoDB支援虛擬生成列上的二級索引;
5)引用子查詢的條件不會被下推;
6)引用了儲存函式的條件也不會被下推。儲存引擎不能呼叫儲存函式;
7)觸發條件也不會被下推。(更多關於觸發條件的資訊可以參考Section 8.2.2.3, “Optimizing Subqueries with the EXISTS Strategy”);
要理解這種優化是如何工作的,首先考慮索引掃描在不使用索引條件下推的情況下是如何進行的:
1)獲取下一行,首先讀取索引元組,然後使用索引元組定位和讀取全錶行;
2)測試適用於此表的部分where條件。根據測試結果接受或拒絕該行。
使用索引條件下推,掃描過程如下:
1)獲取下一行的索引元組(而不是全錶行)
2)測試適用於此表的部分where條件的,並且只能使用索引列進行檢查。如果不滿足條件,則繼續下一行的索引元組。
3)如果滿足條件,則使用索引元組定位並讀取全錶行;If the condition is satisfied, use the index tuple to locate and read the full table row.
4)測試適用於此表的where條件的剩餘部分。根據測試結果接受或拒絕該行。
當索引條件下推被使用的時候,在explain輸出結果中的extra列顯示使用的索引條件。extra列不顯示使用的索引,因為在必須讀取全錶行時不適用。
假如有一張包含個人資訊的表,並且這張表有一個定義為index(zipcode,lastname,firstname)這樣的索引。如果我們知道一個人所在區的郵編但不確定他的姓氏,我們可以像這樣搜尋:
SELECT * FROM people
WHERE zipcode='95054'
AND lastname LIKE '%etrunia%'
AND address LIKE '%Main Street%';
MySQL可以使用索引掃描郵編為‘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';
PS:由於水平有限,譯文中難免存在謬誤,歡迎批評指正。