MySQL--索引條件下推優化

  http://blog.163.com/li_hx/blog/static/1839914132015782821512/

 
 

一 什麼是「索引條件下推」mysql

 
 

「索引條件下推」,稱爲 Index Condition Pushdown (ICP),這是MySQL提供的用某一個索引對一個特定的表從表中獲取元組」,注意咱們這裏特地強調了「一個」,這是由於這樣的索引優化不是用於多表鏈接而是用於單表掃描,確切地說,是單表利用索引進行掃描以獲取數據的一種方式。 sql

 
 

 

 
 

「索引條件下推」的目的數據庫

 
 

用ySQL官方手冊描述:函數

 
 

The goal of ICP is to reduce the number of full-record reads and thereby reduce IO operations. For InnoDB clustered indexes, the complete record is already read into the InnoDB buffer. Using ICP in this case does not reduce IO.fetch

 
 

這句官方描述,一是說明減小完整記錄(一條完整元組)讀取的個數;二是說明對於InnoDB彙集索引無效,只能是對SECOND INDEX這樣的非彙集索引有效。優化

 
 

 

 
 

三 原理ui

 
 

先看實例:this

 
 

 

mysql> set optimizer_switch='index_condition_pushdown=off'; //關閉ICP
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN SELECT * FROM t4 WHERE 1=t4.a4 AND t4.name like 'char%';
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra       |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
|  1 | SIMPLE      | t4    | NULL       | range | a4_i          | a4_i | 28      | NULL |    1 |   100.00 | Using where |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-------------+
1 row in set, 1 warning (0.00 sec)
mysql> set optimizer_switch='index_condition_pushdown=on';  //打開ICP,則Extra列中顯示「Using index condition
Query OK, 0 rows affected (0.00 sec)
mysql> EXPLAIN SELECT * FROM t4 WHERE 1=t4.a4 AND t4.name like 'char%';
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
| id | select_type | table | partitions | type  | possible_keys | key  | key_len | ref  | rows | filtered | Extra                 |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
|  1 | SIMPLE      | t4    | NULL       | range | a4_i          | a4_i | 28      | NULL |    1 |   100.00 | Using index condition |
+----+-------------+-------+------------+-------+---------------+------+---------+------+------+----------+-----------------------+
1 row in set, 1 warning (0.00 sec)
若是打開ICP,則執行計劃的Extra列會顯示「Using index condition」,這代表在。
 
借用網上的2張圖加以改造,並配以解釋,來講明原理,更清晰地說明問題。
 
圖一:不使用ICP技術(過程使用數字符號標示,如①②③等)
 

 


過程解釋:
①:MySQL Server發出讀取數據的命令,這是在執行器中執行以下代碼段,經過函數指針和handle接口調用存儲引擎的索引讀或全表表讀。此處進行的是索引讀。
    if (in_first_read)
    {
      in_first_read= false;
      error= (*qep_tab->read_first_record)(qep_tab); //設定合適的讀取函數,如設定索引讀函數/全表掃描函數
    }
    else
      error= info->read_record(info);
②、③:進入存儲引擎,讀取索引樹,在索引樹上查找,把知足條件的(通過查找,紅色的知足)從表記錄中讀出(步驟④,一般有IO),從存儲引擎返回⑤標識的結果。此處,不只要在索引行進行索引讀取(一般是內存中,速度快。步驟③),還要進行進行步驟④,一般有IO。
⑥:從存儲引擎返回查找到的多條元組給MySQL Server,MySQL Server在⑦獲得較多的元組。
⑦--⑧:⑦到⑧依據WHERE子句條件進行過濾,獲得知足條件的元組。注意在MySQL Server層獲得較多元組,而後才過濾,最終獲得的是少許的、符合條件的元組。
 
圖二:使用ICP技術(過程使用數字符號標示,如①②③等)
 
 

 

 
 
 
過程解釋:
①:MySQL Server發出讀取數據的命令,過程同圖一。
②、③:進入存儲引擎,讀取索引樹,在索引樹上查找,把知足已經下推的條件的(通過查找,紅色的知足)從表記錄中讀出(步驟④,一般有IO),從存儲引擎返回⑤標識的結果。此處,不只要在索引行進行索引讀取(一般是內存中,速度快。步驟③),還要在③這個階段依據下推的條件進行進行判斷,不知足條件的,不去讀取表中的數據,直接在索引樹上進行下一個索引項的判斷,直到有知足條件的,才進行步驟④,這樣,較沒有ICP的方式,IO量減小。
⑥:從存儲引擎返回查找到的少許元組給MySQL Server,MySQL Server在⑦獲得少許的元組。所以比較圖一無ICP的方式,返回給MySQL Server層的便是少許的、符合條件的元組。
 另外,圖中的部件層次關係,再也不進行解釋。
四 實現細節
1 ICP只能用於輔助索引,不能用於彙集索引。
2 ICP只用於單表,不是多表鏈接是的鏈接條件部分(如開篇強調)
若是表訪問的類型爲:
3 EQ_REF/REF_OR_NULL/REF/SYSTEM/CONST: 可使用ICP
4 range:若是不是「index tree only(只讀索引)」,則有機會使用ICP
5 ALL/FT/INDEX_MERGE/INDEX_SCAN:  不可使用ICP


五 上樓spa

1 條件下推,一直是SQL優化的基本規則。因此,條件下推技術是常規技術。數據庫的優化器幾乎不會不實現條件下推優化。指針

2 技術層面,MySQL存在MySQL Server層和儲存層,使得條件下推顯得「有些割裂」。

3 非技術層面,MySQL之因此引入ICP,猜一猜或拍拍腦殼,緣由你懂得。


六 從代碼的角度看

對於圖一的解釋,給出了讀數據的代碼片斷,不管是關閉仍是打開ICP, 從下面給出的函數調用關係能夠看出,2幅圖對應的狀況下,代碼路徑是一致的.

首條元組讀取調用關係(藍色標識和非首條元組不一樣之處):

JOIN::exec()->do_select()->sub_select()->join_init_read_record()->rr_quick()->
  QUICK_RANGE_SELECT::get_next()->ha_innobase::multi_range_read_next()->
  DsMrr_impl::dsmrr_next()->handler::multi_range_read_next()->
  handler::read_range_first()->handler::ha_index_read_map()->
  handler::index_read_map()->ha_innobase::index_read()

 

除首條元組讀取調用關係(藍色標識和首條元組不一樣之處)

JOIN::exec()->do_select()->sub_select()->join_init_read_record()->rr_quick()->
  QUICK_RANGE_SELECT::get_next()->ha_innobase::multi_range_read_next()->
  DsMrr_impl::dsmrr_next()->handler::multi_range_read_next()->
  handler::read_range_next()->handler::ha_index_next()->  ha_innobase::index_next()->ha_innobase::general_fetch()

相關文章
相關標籤/搜索