大家好,我是老三,今天分享一個小知識點——索引下推,
如果你在面試中,聽到MySQL5.6”、“索引優化” 之類的詞語,你就要立馬get到,這個問的是“索引下推”,
什么是索引下推
索引下推(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,

那接下來的步驟是什么呢?
沒有使用ICP
在MySQL 5.6之前,存盤引擎根據通過聯合索引找到name likelike '張%' 的主鍵id(1、4),逐一進行回表掃描,去聚簇索引找到完整的行記錄,server層再對資料根據age=10進行篩選,
我們看一下示意圖:

可以看到需要回表兩次,把我們聯合索引的另一個欄位age浪費了,
使用ICP
而MySQL 5.6 以后, 存盤引擎根據(name,age)聯合索引,找到name likelike '張%',由于聯合索引中包含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";
參考:
[1].《 MySQL技術內幕 InnoDB存盤引擎》
[2]. 《MySQL實戰45講》
[3]. MySQL索引下推(ICP)簡單理解及例子
[4]. 一文讀懂什么是MySQL索引下推(ICP)
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/299223.html
標籤:其他
下一篇:2021數模國賽A題思路及代碼
