標籤:
Index Condition Pushdown(ICP)索引條件下推最佳化適用於mysql在table中通過index檢索資料行,沒有ICP,儲存引擎層遍曆索引來定位基表(base table)上的資料行並且把它們返回給server層,由server層來計算過濾where語句.使用ICP,並且where語句的部分篩選條件可以通過index來檢測,則mysql server層會講部分where 條件下推給儲存引擎層。儲存引擎通過使用index條目來評估下推的index condition,並且僅僅讀取滿足index condition的資料行。ICP可以減少儲存引擎access 基表和Server層access storage engine的次數;(圖引用網友)
Index Condition Pushdown 最佳化用作range,ref,eq_ref和ref_or_null 存取方法access表的所有行時。這策略可以用作Innodb和MyISAM表(注意5.6版本Index Condition pushdown不支援分區表,5.7支援)對於Innodb表,ICP只能用於二級索引,ICP的目標是減少基表access次數,從而減少磁碟IO操作。對於INNoDB clustered 索引,所有記錄已經被讀進Innodb buffer,這種情況下用ICP不能減少IO次數。
為了瞭解最佳化器如何工作,考慮當ICP沒被使用時,Index掃描是怎麼經行的?
1:server層為了得到下一個資料行,儲存引擎讀取該資料行對應的Index 條目(元組),通過該Index條目來定位返回完整的資料行(基表);
2: server層用while 語句條件來檢測返回資料行,資料行的accept 或者 reject 基於檢測結果。
當ICP使用時,index掃描過程:(不僅用index 來定位元據行,而且用where condition中包含的index columns來過濾資料,打個比方,根據mysql index最左首碼原則,where ‘xxx‘ = ‘hello‘ and ‘yyy‘ = ‘% xxx%‘,儲存引擎只會用 ‘xxx‘列來定位元據,而‘yyy’是模糊比對,不會使用,用不用ICP,兩種情況掃描index是一樣,不過用ICP,會額外使用‘%yyy%‘匹配對聯合索引‘yyy’,僅讀取和返回滿足‘hello‘和‘%xxx%’的完整資料行,而不用Icp,讀取和返回的是單獨滿足‘hello‘列值的資料行,)
1: 儲存引擎獲得對應的Index條目(非基表的資料行)。
2:用where condition中的包含的index columns 來檢測對應的Index columns,如果condition不滿足,處理下一條index 條目。
3: 如果condition成立,用對應的index 條目來定位返回基表完整的資料行。
4: 用where condition剩餘的部分來檢測storage engine返回的資料行。
當ICP 使用時,explain extra列顯示 Using index condition.
未使用ICP:
使用ICP:
在ICP最佳化開啟時,在儲存引擎端首先用索引過濾可以過濾的where條件(where中的條件列包含index列),然後再用索引做data access,被index condition過濾掉的資料不必讀取,也不會返回server端,如果where條件列中有不包含在索引列中的列,則根據storage engine ICP返回的資料行再做where判斷(where去除index columns的列),所以這種情況下server 層應該在加上Using where小塊,同上; 見例子:
use empolyees
mysql> desc employees.employees;+------------+---------------+------+-----+---------+-------+| Field | Type | Null | Key | Default | Extra |+------------+---------------+------+-----+---------+-------+| emp_no | int(11) | NO | PRI | NULL | || birth_date | date | NO | | NULL | || first_name | varchar(14) | NO | | NULL | || last_name | varchar(16) | NO | | NULL | || gender | enum(‘M‘,‘F‘) | NO | | NULL | || hire_date | date | NO | | NULL | |+------------+---------------+------+-----+---------+-------+6 rows in set (0.09 sec)
mysql> alter table employees add index idx_fn_ln (first_name,last_name );//添加聯合索引Query OK, 0 rows affected (3.98 sec)Records: 0 Duplicates: 0 Warnings: 0
Index Condition Pushdown開啟的情況下
mysql> explain select * from employees where first_name =‘Mary‘ and last_name like ‘%man‘;+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-----------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-----------------------+| 1 | SIMPLE | employees | ref | idx_fn_ln | idx_fn_ln | 16 | const | 224 | Using index condition |+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-----------------------+1 row in set (0.00 sec)
關閉的情況下:
mysql> set optimizer_switch = ‘index_condition_pushdown=off‘; //關閉index condition pushdownQuery OK, 0 rows affected (0.02 sec)mysql> explain select * from employees where first_name =‘Mary‘ and last_name like ‘%man‘;+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------------+| 1 | SIMPLE | employees | ref | idx_fn_ln | idx_fn_ln | 16 | const | 224 | Using where |+----+-------------+-----------+------+---------------+-----------+---------+-------+------+-------------+1 row in set (0.00 sec)
看where語句中包含上述聯合索引,並且包含一個非索引列:
mysql> set optimizer_switch=‘index_condition_pushdown=on‘;Query OK, 0 rows affected (0.00 sec)mysql> explain select * from employees where first_name =‘Mary‘ and last_name =‘%man‘ and gender =‘M‘;+----+-------------+-----------+------+---------------+-----------+---------+-------------+------+------------------------------------+| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |+----+-------------+-----------+------+---------------+-----------+---------+-------------+------+------------------------------------+| 1 | SIMPLE | employees | ref | idx_fn_ln | idx_fn_ln | 34 | const,const | 1 | Using index condition; Using where |+----+-------------+-----------+------+---------------+-----------+---------+-------------+------+------------------------------------+1 row in set (0.01 sec)
同樣有using index condition,不過index過濾後,Server還要根據gender列來判斷一下 storage engine返回的值;
ICP只能用於二級索引,不能用於主索引。
也不是全部where條件都可以用ICP篩選,如果某where條件的欄位不在索引中,當然還是要讀取整條記錄做篩選,在這種情況下,仍然要到server端做where篩選。
ICP的加速效果取決於在儲存引擎內通過ICP篩選掉的資料的比例。
本文使用employees資料庫表和資料在這裡************下載,該庫功能資料齊全,employees_db-full-1.0.6.tar.bz2;
MySQL Index Condition Pushdown(ICP)最佳化