MySQL帶你秒懂索引下推
索引下推(Index Condition Pushdown
,簡稱ICP
),是MySQL5.6
版本的新特性,它能減少回表查詢次數,提高查詢效率。
一、索引下推優化的原理
我們先簡單瞭解一下MySQL大概的架構:
MySQL服務層負責SQL語法解析、生成執行計劃等,並調用存儲引擎層去執行數據的存儲和檢索。
索引下推
的下推其實就是指將部分上層(服務層)負責的事情,交給瞭下層(引擎層)去處理。
我們來具體看一下,在沒有使用ICP的情況下,MySQL的查詢:
- 存儲引擎讀取索引記錄;
- 根據索引中的主鍵值,定位並讀取完整的行記錄;
- 存儲引擎把記錄交給Server層去檢測該記錄是否滿足WHERE條件。
使用ICP的情況下,查詢過程:
- 存儲引擎讀取索引記錄(不是完整的行記錄);
- 判斷WHERE條件部分能否用索引中的列來做檢查,條件不滿足,則處理下一行索引記錄;
- 條件滿足,使用索引中的主鍵去定位並讀取完整的行記錄(就是所謂的回表);
- 存儲引擎把記錄交給Server層,Server層檢測該記錄是否滿足WHERE條件的其餘部分。
二、索引下推的具體實踐
理論比較抽象,我們來上一個實踐。
使用一張用戶表tuser
,表裡創建聯合索引(name, age)。
如果現在有一個需求:檢索出表中名字第一個字是張,而且年齡是10歲的所有用戶。那麼,SQL語句是這麼寫的:
select * from tuser where name like '張%' and age=10;
假如你瞭解索引最左匹配原則,那麼就知道這個語句在搜索索引樹的時候,隻能用 張,找到的第一個滿足條件的記錄id為1。
那接下來的步驟是什麼呢?
1、沒有使用ICP
在MySQL 5.6
之前,存儲引擎根據通過聯合索引找到name like
‘張%’ 的主鍵id(1、4),逐一進行回表掃描,去聚簇索引找到完整的行記錄,server
層再對數據根據age=10
進行篩選。
我們看一下示意圖:
可以看到需要回表兩次,把我們聯合索引的另一個字段age
浪費瞭。
2、使用ICP
而MySQL 5.6
以後, 存儲引擎根據(name
,age
)聯合索引,找到name like '張%
‘,由於聯合索引中包含age
列,所以存儲引擎直接再聯合索引裡按照age=10
過濾。按照過濾後的數據再一一進行回表掃描。
我們看一下示意圖:
可以看到隻回表瞭一次。
除此之外我們還可以看一下執行計劃,看到Extra
一列裡 Using index condition
,這就是用到瞭索引下推。
+----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | tuser | NULL | range | na_index | na_index | 102 | NULL | 2 | 25.00 | Using index condition | +----+-------------+-------+------------+-------+---------------+----------+---------+------+------+----------+-----------------------+
三、索引下推使用條件
- 隻能用於
range
、ref
、eq_ref
、ref_or_null
訪問方法; - 隻能用於
InnoDB
和MyISAM
存儲引擎及其分區表; - 對
InnoDB
存儲引擎來說,索引下推隻適用於二級索引(也叫輔助索引);
索引下推的目的是為瞭減少回表次數,也就是要減少IO操作。對於InnoDB的聚簇索引來說,
數據和索引
是在一起的,不存在回表這一說。
- 引用瞭子查詢的條件不能下推;
- 引用瞭存儲函數的條件不能下推,因為存儲引擎無法調用存儲函數。
相關系統參數:
索引條件下推默認是開啟的,可以使用系統參數optimizer_switch來控制器是否開啟。
查看默認狀態:
mysql> select @@optimizer_switch\G; *************************** 1. row *************************** @@optimizer_switch: index_merge=on,index_merge_union=on,index_merge_sort_union=on,index_merge_intersection=on,engine_condition_pushdown=on,index_condition_pushdown=on,mrr=on,mrr_cost_based=on,block_nested_loop=on,batched_key_access=off,materialization=on,semijoin=on,loosescan=on,firstmatch=on,duplicateweedout=on,subquery_materialization_cost_based=on,use_index_extensions=on,condition_fanout_filter=on,derived_merge=on 1 row in set (0.00 sec)
切換狀態:
set optimizer_switch="index_condition_pushdown=off"; set optimizer_switch="index_condition_pushdown=on";
到此這篇關於幾分鐘搞懂MySQL索引下推的文章就介紹到這瞭,更多相關MySQL索引下推內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!