索引下推 ICP(MySQL 5.6+)

一句话总结

没有 ICP:二级索引查到 id → 回表拿整行 → 在 server 层过滤其他条件。有 ICP:回表之前先在索引层面把不符合条件的行过滤掉,减少回表次数。核心是”把过滤操作从 server 层下推到存储引擎层”。


🌰 没有 ICP 的世界

 
-- 联合索引:INDEX (name, age)
 
SELECT * FROM user WHERE name LIKE '张%' AND age > 25;
 

没有 ICP(MySQL 5.6 之前):

 
Step 1: 用 idx_name_age 找到所有 name LIKE '张%' 的 id
 
        └─ 找到了 id = [5, 8, 12, 15, 20, ...]  共 100 个
 
Step 2: 拿着这 100 个 id → 回表 100 次
 
        └─ 去聚簇索引拿整行数据
 
Step 3: 在 server 层过滤 age > 25
 
        └─ 100 行里只有 30 行满足 → 丢掉 70 行
 
        └─ 那 70 次回表白干了!
 

问题:age > 25 这个条件明明在索引里有(idx_name_age 包含了 age),但因为没有 ICP,MySQL 傻乎乎地先把所有 name 匹配的行都回表了,然后在 server 层才过滤 age。

70 次回表 = 70 次磁盘 IO = 白白浪费的。


有 ICP 的世界

 
-- 同样的索引,同样的 SQL
 
SELECT * FROM user WHERE name LIKE '张%' AND age > 25;
 

有 ICP(MySQL 5.6+):

 
Step 1: 用 idx_name_age 找到所有 name LIKE '张%' 的行
 
        └─ 遍历索引时,顺手检查 age > 25
 
Step 2: 只有同时满足 name LIKE '张%' AND age > 25 的 id 才回表
 
        └─ 30 个 id → 回表 30 次
 
Step 3: 直接返回
 

ICP 把 age > 25 的过滤”下推”到了存储引擎层(索引遍历时做),而不是全部回表再到 server 层过滤。回表次数从 100 次降到了 30 次。


覆盖索引 vs ICP

容易跟覆盖索引搞混。核心区别:

覆盖索引ICP
回表了吗❌ 不回✅ 回(但更少)
做了什么查的列全在索引里,不需要回表条件提前在索引里过滤,只回表需要的行
ExtraUsing indexUsing index condition
效果省掉回表减少回表次数

三种情况对比

 
-- 索引:INDEX (name, age)
 
-- 情况 1:没 ICP、没覆盖 → 最慢
 
SELECT * FROM user WHERE name LIKE '张%' AND age > 25;
 
-- 没有 ICP 时:回表 100 次 → server 层过滤 100 行
 
-- 情况 2:有 ICP → 更快
 
-- MySQL 5.6+ 默认启用 ICP
 
SELECT * FROM user WHERE name LIKE '张%' AND age > 25;
 
-- Extra: Using index condition
 
-- 回表 30 次(只回满足两个条件的行)
 
-- 情况 3:覆盖索引 → 最快
 
SELECT name, age FROM user WHERE name LIKE '张%' AND age > 25;
 
-- Extra: Using index
 
-- 0 次回表
 

ICP 的适用条件

必须同时满足

  1. 联合索引 — ICP 在单列索引上没有意义(只有一个条件)

  2. 索引能定位到范围LIKE '张%'><BETWEEN 等范围匹配

  3. 条件涉及索引里的额外列 — 除了最左前缀条件外的其他索引列

  4. InnoDB 或 MyISAM — 两种引擎都支持

什么时候不生效

 
-- ❌ 条件列不在索引里
 
-- 索引:INDEX (name)
 
SELECT * FROM user WHERE name LIKE '张%' AND age > 25;
 
-- age 不在索引里 → 没法下推
 
-- ❌ 主键索引
 
-- ICP 只对二级索引生效,聚簇索引不需要 ICP(已经在数据页了)
 
-- ❌ 条件无法在索引层面判断
 
-- 索引:INDEX (name)
 
SELECT * FROM user WHERE name = '张三' AND age > 25;
 
-- name 精确匹配时只返回一条或几条,回表成本很低,ICP 收益不大
 
-- (MySQL 实际也会下推,但效果不明显)
 

经验数字:ICP 能省多少?

场景无 ICP 回表次数有 ICP 回表次数节省
LIKE '张%' 匹配 1000 行,age 过滤剩 100 行1000 次100 次90%
LIKE '张%' 匹配 100 行,age 过滤剩 80 行100 次80 次20%
name > 'A' 匹配 10 万行,age 过滤剩 1 万行10 万次1 万次90%

范围匹配越宽泛、后续条件过滤性越强 → ICP 收益越大。


怎么聊 ICP

 
延伸提问:"说说索引下推?"
 
你:
 
"ICP 是 MySQL 5.6 引入的优化,核心思想是:
 
把 WHERE 条件里那些可以用索引判断的部分,
 
从 server 层"下推"到存储引擎层提前过滤。
 
举个例子:联合索引 (name, age),查 WHERE name LIKE '张%' AND age > 25。
 
没有 ICP 的话,MySQL 拿着 '张%' 找到的 id 全部回表,到 server 层再过滤 age。
 
有 ICP,遍历索引时顺便把 age > 25 检查了,只回表满足两个条件的行。
 
效果取决于后面条件的过滤性——
 
age > 25 能过滤掉 90% 的行,回表就省 90%。
 
如果过滤性差,省得就少,但总归不会慢。"
 
延伸提问:"怎么看有没有用到 ICP?"
 
"EXPLAIN 的 Extra 列显示 Using index condition。"
 

记忆口诀

ICP = 回表前先过滤,少做无用功。

联合索引范围查,后续条件下推用。

覆盖索引不回表,ICP 少回表——两个加一起,性能翻倍跑。

EXPLAIN 看 Extra:Using index condition,ICP 在工作。

一图流(Mermaid)


flowchart TD

    A["WHERE name LIKE '张%' AND age>25"] --> B{有 ICP?}

    B -->|否| C[拿所有'张%'的id 回表100次]

    C --> D[server层过滤age 丢70行 白回表]

    B -->|是| E[遍历索引时顺手查 age>25]

    E --> F[只回表满足两条件的30次]

    F --> G[少70次IO ✅]

    H["覆盖索引: 列全在索引"] --> I[0次回表 最快]

▶ 对应实操:09-事务实操

速记卡(面试闪卡)

Q1:一句话讲清「索引下推 ICP(MySQL 5.6+)」到底是什么?

A:索引下推 ICP 把 WHERE 里能用索引判断的条件,从 server 层下推到存储引擎,回表前先过滤少做无用功。

Q2:一、没有 ICP 的世界 —— 怎么理解? —— 怎么理解?

A:没 ICP 时,二级索引找到匹配的 id 就全部回表(查整行),到 server 层才过滤 age>25,结果 100 次回表 70 次白干。就像快递员把整栋楼的包裹都搬下楼,到了门口才看收件人名字——搬错了 70 个。

Q3:二、有 ICP 的世界 —— 怎么理解? —— 怎么理解?

A:有 ICP,遍历索引时顺手检查 age>25,只回表满足两个条件的行,回表从 100 次降到 30 次。等于快递员在货架上就瞄一眼名字,只搬该搬的。核心:过滤下推(Index Condition Pushdown)。

Q4:三、ICP vs 覆盖索引 —— 怎么理解? —— 怎么理解?

A:覆盖索引直接不回表(Extra: Using index),ICP 仍回表但只回表需要的行(Extra: Using index condition)。覆盖索引省掉回表,ICP 减少回表次数,两者叠加最香。看生效:EXPLAIN 的 Extra 列出现 Using index condition。

Q5:四、ICP 适用条件与收益 —— 怎么理解? —— 怎么理解?

A:生效需满足:联合索引(单列无意义)、能定位范围(LIKE/BETWEEN)、条件涉及索引额外列、InnoDB/MyISAM。主键索引、条件列不在索引里不生效。范围越宽、后续过滤越强,省得越多(极端省 90% 回表)。

Q6:核心速记主线有哪些?

  • 没有 ICP:二级索引全回表,server 层才过滤

  • 有 ICP:回表前在索引层先过滤,少回表

  • 覆盖索引不回表,ICP 少回表,二者叠加最佳

  • 看 EXPLAIN Extra: Using index condition 即生效

口诀

A:索引下推真奇妙,

回表前先把关牢;

覆盖索引不回跑,

ICP 省力又高效。

相关链接

相关链接