1. 程式人生 > 實用技巧 >MySQL 5.6新特性 -- Index Condition Pushdown

MySQL 5.6新特性 -- Index Condition Pushdown

原文地址

Index Condition Pushdown(ICP)是針對mysql使用索引從表中檢索行資料時的一種優化方法。

  • 在沒有ICP特性之前,儲存引擎根據索引去基表查詢並將資料返回給mysql server,mysql server再根據where條件進行資料過濾。

  • 有了ICP之後,在取出索引的同時,判斷是否可以根據索引中的列進行where條件過濾,也就是將where的部分過濾操作放在了儲存引擎層。這樣就會減少上層sql層對記錄的獲取。

ICP優化支援range、ref、eq_ref、ref_or_null型別的查詢。查詢優化器會給出相應的提示:Using index condition。當開啟ICP後,在執行計劃的extra列會顯示:Using index condition。

ICP支援innodb、myisam表。對於innodb表,ICP只是用於輔助索引。

在5.6中,ICP不支援分割槽表。這個問題在mysql 5.7中得到解決。

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

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

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

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

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

沒有ICP之前:

開啟ICP之後,就變成:

預設是開啟ICP的,手動開啟/關閉ICP:

set` `optimizer_switch = ``'index_condition_pushdown=off'``;``set` `optimizer_switch = ``'index_condition_pushdown=on'``;

 

測試過程

1.環境準備

#mysql 5.6.25``#關閉結果快取``mysql> ``set` `global` `query_cache_size=0;``mysql> ``set` `query_cache_type=``off``;` `#查看錶結構``mysql> show ``create` `table` `employees\G``*************************** 1. row ***************************``    ``Table``: employees``Create` `Table``: ``CREATE` `TABLE` ``employees` (`` ```emp_no` ``int``(11) ``NOT` `NULL``,`` ```birth_date` ``date` `NOT` `NULL``,`` ```first_name` ``varchar``(14) ``NOT` `NULL``,`` ```last_name` ``varchar``(16) ``NOT` `NULL``,`` ```gender` enum(``'M'``,``'F'``) ``NOT` `NULL``,`` ```hire_date` ``date` `NOT` `NULL``,`` ``PRIMARY` `KEY` `(`emp_no`),`` ``KEY` ``idx_first_last_name` (`first_name`,`last_name`)``) ENGINE=InnoDB ``DEFAULT` `CHARSET=utf8``1 row ``in` `set` `(0.00 sec)` `mysql>

2.開啟ICP後進行測試

mysql> ``set` `profiling = 1;``mysql> ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``mysql> explain ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``mysql> show profiles;``mysql> show profile cpu,block io ``for` `query 1;

3.關閉ICP後進行測試

mysql> ``set` `optimizer_switch=``'index_condition_pushdown=off'``;``mysql> ``set` `profiling = 1;``mysql> ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``mysql> explain ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``mysql> show profiles;``mysql> show profile cpu,block io ``for` `query 1;

4.結果比較

開啟ICP後的執行計劃:執行計劃中extra部分的內容是"using index condition"

mysql> explain ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-----------------------+``| id | select_type | ``table`   `| type | possible_keys    | ``key`         `| key_len | ref  | ``rows` `| Extra         |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-----------------------+``| 1 | SIMPLE   | employees | ref | idx_first_last_name | idx_first_last_name | 44   | const | 224 | Using ``index` `condition |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-----------------------+

關閉ICP後的執行計劃:執行計劃中extra部分的內容是"using where"

mysql> explain ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name ``like` `'%sig'` `;``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-------------+``| id | select_type | ``table`   `| type | possible_keys    | ``key`         `| key_len | ref  | ``rows` `| Extra    |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-------------+``| 1 | SIMPLE   | employees | ref | idx_first_last_name | idx_first_last_name | 44   | const | 224 | Using ``where` `|``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------+------+-------------+

 

開啟ICP後的profile內容:Sending data部分的值是0.000212s

mysql> show profile cpu,block io ``for` `query 1;``+``----------------------+----------+----------+------------+--------------+---------------+``| Status        | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |``+``----------------------+----------+----------+------------+--------------+---------------+``| starting       | 0.000114 | 0.000000 |  0.000000 |      0 |       0 |``| checking permissions | 0.000007 | 0.000000 |  0.000000 |      0 |       0 |``| Opening tables    | 0.000018 | 0.000000 |  0.000000 |      0 |       0 |``| init         | 0.000034 | 0.000000 |  0.000000 |      0 |       0 |``| System lock     | 0.000008 | 0.000000 |  0.000000 |      0 |       0 |``| optimizing      | 0.000023 | 0.000000 |  0.000000 |      0 |       0 |``| ``statistics`      `| 0.000383 | 0.000000 |  0.000000 |      0 |       0 |``| preparing      | 0.000019 | 0.000000 |  0.000000 |      0 |       0 |``| executing      | 0.000002 | 0.000000 |  0.000000 |      0 |       0 |``| Sending data     | 0.000212 | 0.000000 |  0.000000 |      0 |       0 |``| ``end`         `| 0.000004 | 0.000000 |  0.000000 |      0 |       0 |``| query ``end`      `| 0.000004 | 0.000000 |  0.000000 |      0 |       0 |``| closing tables    | 0.000006 | 0.000000 |  0.000000 |      0 |       0 |``| freeing items    | 0.000020 | 0.000000 |  0.000000 |      0 |       0 |``| cleaning up     | 0.000011 | 0.000000 |  0.000000 |      0 |       0 |``+``----------------------+----------+----------+------------+--------------+---------------+

關閉ICP後的profile內容:Sending data部分的值是0.010990s

mysql> show profile cpu,block io ``for` `query 1;``+``----------------------+----------+----------+------------+--------------+---------------+``| Status        | Duration | CPU_user | CPU_system | Block_ops_in | Block_ops_out |``+``----------------------+----------+----------+------------+--------------+---------------+``| starting       | 0.000165 | 0.000000 |  0.000000 |      0 |       0 |``| checking permissions | 0.000022 | 0.000000 |  0.000000 |      0 |       0 |``| Opening tables    | 0.000027 | 0.000000 |  0.000000 |      0 |       0 |``| init         | 0.000039 | 0.000000 |  0.000000 |      0 |       0 |``| System lock     | 0.000008 | 0.000000 |  0.000000 |      0 |       0 |``| optimizing      | 0.000037 | 0.001000 |  0.000000 |      0 |       0 |``| ``statistics`      `| 0.000483 | 0.001000 |  0.000000 |      0 |       0 |``| preparing      | 0.000022 | 0.000000 |  0.000000 |      0 |       0 |``| executing      | 0.000002 | 0.000000 |  0.000000 |      0 |       0 |``| Sending data     | 0.010990 | 0.007999 |  0.002000 |      0 |       0 |``| ``end`         `| 0.000009 | 0.000000 |  0.000000 |      0 |       0 |``| query ``end`      `| 0.000005 | 0.000000 |  0.000000 |      0 |       0 |``| closing tables    | 0.000008 | 0.000000 |  0.000000 |      0 |       0 |``| freeing items    | 0.000028 | 0.000000 |  0.000000 |      0 |       0 |``| cleaning up     | 0.000014 | 0.000000 |  0.000000 |      0 |       0 |``+``----------------------+----------+----------+------------+--------------+---------------+

  

其它:

當sql使用覆蓋索引時,不支援ICP優化方法

mysql> explain ``select` `first_name,last_name ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name=``'Porenta'` `;``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+--------------------------+``| id | select_type | ``table`   `| type | possible_keys    | ``key`         `| key_len | ref     | ``rows` `| Extra          |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+--------------------------+``| 1 | SIMPLE   | employees | ref | idx_first_last_name | idx_first_last_name | 94   | const,const |  1 | Using ``where``; Using ``index` `|``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+--------------------------+``mysql> explain ``select` `* ``from` `employees ``where` `first_name=``'Anneke'` `and` `last_name=``'Porenta'` `;``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+-----------------------+``| id | select_type | ``table`   `| type | possible_keys    | ``key`         `| key_len | ref     | ``rows` `| Extra         |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+-----------------------+``| 1 | SIMPLE   | employees | ref | idx_first_last_name | idx_first_last_name | 94   | const,const |  1 | Using ``index` `condition |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+-----------------------+