1. 程式人生 > >MySQL5.6之Index Condition Pushdown(ICP,索引條件下推)

MySQL5.6之Index Condition Pushdown(ICP,索引條件下推)

轉載 :https://blog.csdn.net/z69183787/article/details/53954914

http://mdba.cn/2014/01/21/index-condition-pushdownicp%E7%B4%A2%E5%BC%95%E6%9D%A1%E4%BB%B6%E4%B8%8B%E6%8E%A8/

ICP(index condition pushdown)是mysql利用索引(二級索引)元組和篩欄位在索引中的where條件從表中提取資料記錄的一種優化操作。ICP的思想是:儲存引擎在訪問索引的時候檢查篩選欄位在索引中的where條件(pushed index condition,推送的索引條件),如果索引元組中的資料不滿足推送的索引條件,那麼就過濾掉該條資料記錄。ICP(優化器)儘可能的把index condition的處理從server層下推到storage engine層。storage engine使用索引過過濾不相關的資料,僅返回符合index condition條件的資料給server層。也是說資料過濾儘可能在storage engine層進行,而不是返回所有資料給server層,然後後再根據where條件進行過濾。使用ICP(mysql 5.6版本以前)和沒有使用ICP的資料訪問和提取過程如下(插圖來在

MariaDB Blog):

優化器沒有使用ICP時,資料訪問和提取的過程如下:

1)    當storage engine讀取下一行時,首先讀取索引元組(index tuple),然後使用索引元組在基表中(base table)定位和讀取整行資料。

2)    sever層評估where條件,如果該行資料滿足where條件則使用,否則丟棄。

3)    執行1),直到最後一行資料。

index-access-2phases

優化器使用ICP時,server層將會把能夠通過使用索引進行評估的where條件下推到storage engine層。資料訪問和提取過程如下:

1)    storage engine從索引中讀取下一條索引元組。

2)    storage engine使用索引元組評估下推的索引條件。如果沒有滿足wehere條件,storage engine將會處理下一條索引元組(回到上一步)。只有當索引元組滿足下推的索引條件的時候,才會繼續去基表中讀取資料。

3)    如果滿足下推的索引條件,storage engine通過索引元組定位基表的行和讀取整行資料並返回給server層。

4)    server層評估沒有被下推到storage engine層的where條件,如果該行資料滿足where條件則使用,否則丟棄。

index-access-with-icp

而使用ICP時,如果where條件的一部分能夠通過使用索引中的欄位進行評估,那麼mysql server把這部分where條件下推到storage engine(儲存引擎層)。儲存引擎通過索引元組的索引列資料過濾不滿足下推索引條件的資料行。

索引條件下推的意思就是篩選欄位在索引中的where條件從server層下推到storage engine層,這樣可以在儲存引擎層過濾資料。由此可見,ICP可以減少儲存引擎訪問基表的次數和mysql server訪問儲存引擎的次數。

注意一下ICP的使用條件:

  1. 只能用於二級索引(secondary index)。
  2. explain顯示的執行計劃中type值(join 型別)為range、 ref、 eq_ref或者ref_or_null。且查詢需要訪問表的整行資料,即不能直接通過二級索引的元組資料獲得查詢結果(索引覆蓋)。
  3. ICP可以用於MyISAM和InnnoDB儲存引擎,不支援分割槽表(5.7將會解決這個問題)。

 

ICP的開啟優化功能與關閉

MySQL5.6可以通過設定optimizer_switch([global|session],dynamic)變數開啟或者關閉index_condition_push優化功能,預設開啟。

mysql > set optimizer_switch=’index_condition_pushdown=on|off’

用explain檢視執行計劃時,如果執行計劃中的Extra資訊為“using index condition”,表示優化器使用的index condition pushdown。

在mysql5.6以前,還沒有采用ICP這種查詢優化,where查詢條件中的索引條件在某些情況下沒有充分利用索引過濾資料。假設一個組合索引(多列索引)K包含(c1,c2,…,cn)n個列,如果在c1上存在範圍掃描的where條件,那麼剩餘的c2,…,cn這n-1個上索引都無法用來提取和過濾資料(不管不管是唯一查詢還是範圍查詢),索引記錄沒有被充分利用。即組合索引前面欄位上存在範圍查詢,那麼後面的部分的索引將不能被使用,因為後面部分的索引資料是無序。比如,索引key(a,b)中的元組資料為(0,100)、(1,50)、(1,100) ,where查詢條件為 a < 2 and b = 100。由於b上得索引資料並不是連續區間,因為在讀取(1,50)之後不再會讀取(1,100),mysql優化器在執行索引區間掃描之後也不再掃描組合索引其後面的部分。

表結構定義如下:

1

2

3

4

5

6

7

8

9

10

11

CREATE TABLE `person` (

`person_id` smallint(5) unsigned NOT NULL AUTO_INCREMENT,

`postadlcode` int(11) DEFAULT NULL,

`age` tinyint(4) DEFAULT NULL,

`first_name` varchar(45) NOT NULL,

`last_name` varchar(45) NOT NULL,

`last_update` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,

PRIMARY KEY (`person_id`),

KEY `idx_p_a` (`postadlcode`,`age`),

KEY `idx_f_l` (`first_name`,`last_name`)

) ENGINE=InnoDB  DEFAULT CHARSET=utf8

關閉ICP優化,Extra資訊為“Using Where”

1

2

3

4

5

6

7

mysql> set optimizer_switch = "index_condition_pushdown=off";

mysql> explain select  *   from person  where postadlcode between 300000 and 400000 and age > 40;

+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra       |

+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

|  1 | SIMPLE      | person | range | idx_p_a       | idx_p_a | 7       | NULL |   21 | Using where |

+----+-------------+--------+-------+---------------+---------+---------+------+------+-------------+

開啟ICP之後,Extra資訊為“Using Index Condition”

1

2

3

4

5

6

7

mysql> set optimizer_switch = "index_condition_pushdown=on";

mysql> explain select  *   from person  where postadlcode between 300000 and 400000 and age > 40;

+----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+

| id | select_type | table  | type  | possible_keys | key     | key_len | ref  | rows | Extra                 |

+----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+

|  1 | SIMPLE      | person | range | idx_p_a       | idx_p_a | 7       | NULL |   21 | Using indexcondition |

+----+-------------+--------+-------+---------------+---------+---------+------+------+-----------------------+

參考資料:

The MySQL range access method explained (需要梯子)

MySQL 5.6: Index Condition Pushdown (需要梯子)

 Index Condition Pushdown Optimization

 

 

轉載: https://blog.csdn.net/zxm1306192988/article/details/80255747 

 

優化關係 SQL 查詢的一項基本技術是,將外層查詢塊的 WHERE 子句中的謂詞移入所包含的較低層查詢塊(例如檢視),從而能夠提早進行資料過濾以及有可能更好地利用索引。

這在分割槽資料庫環境中甚至更為重要,其原因在於,提早進行過濾有可能減少必須在資料庫分割槽之間傳遞的資料量。

此優化技術在 SQL 中被稱為謂詞下推(Predicate pushdown) 。 
基本策略是,始終將過濾表示式儘可能移至靠近資料來源的位置。

事實主流的資料庫基本上都支援這種方式的優化。其原則是在一個查詢樹中,對於任何選擇都儘量早做選擇,然後進行一步的處理.可見我們並不需要改寫這個sql,優化器會自動去幫我們做這種優化.

如: 
有表: 
t_student(student_id, student_name, student_age) 
t_score(score_id, student_id, course_id, score_number)

優化的sql:

EXPLAIN SELECT * FROM t_student t1 right JOIN (
SELECT * from t_score WHERE score_id=2
) t2
ON t1.student_id=t2.student_id;
1
2
3
4
先看 id 為2的行,先查詢 t_score,由於有 score_id=2 根據主鍵索引直接查到對應行; 
然後看 第一行,查詢id為2 行生成的臨時表,表中只有一條記錄,所以查詢型別為 system; 
最後執行 第二行,直接根據 上面查到行的 student_id 根據 t1 表的主鍵索引直接找到。

優化前的sql:

EXPLAIN SELECT *
FROM t_student,t_score
WHERE t_score.student_id=t_student.student_id
AND t_score.score_id=2;
1
2
3
4


可以看到先查詢 t_score 表,ref 為 const 型別,說明 使用了過濾條件 t_score.score_id=2 ; 
即 在 掃描 t_score 表時就使用了過濾條件,而不是等到和 t_student 表連線之後才過濾。 
這就說明 mysql 優化器使用了謂詞下推技術 對我們的sql 語句進行了優化。