1. 程式人生 > >MySQL查詢優化之索引條件下推

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:由於水平有限,譯文中難免存在謬誤,歡迎批評指正。