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 |``+``----+-------------+-----------+------+---------------------+---------------------+---------+-------------+------+-----------------------+