索引下推(ICP,Index Condition Pushdown)

**索引下推(ICP,Index Condition Pushdown)**是 MySQL 5.6+ 默认开启的优化:把 WHERE 里能在索引上判断的条件,下推到存储引擎层,在遍历索引时就过滤掉不满足条件的行,从而大幅减少回表次数和 I/O

下面用最清晰、面试可直接背的方式讲。


一、一句话理解

  • 没有 ICP :只按索引最左前缀过滤 → 所有匹配前缀的都要回表 → Server 层再过滤 → 大量无效回表。
  • 有 ICP :索引里有的字段条件,在索引阶段就过滤 → 只回表那些真正符合全部条件的 → 回表变少、性能变快

图书馆类比(好记):

  • 索引=目录(姓名、年龄、书架号)
  • 查:姓名=张三 AND 年龄=20
  • 无 ICP:把所有"张三"的目录都拿出来,逐个去书架拿书,再看年龄是不是20。
  • 有 ICP:直接在目录里筛出"张三+年龄20",只拿这几本去书架

二、原理与流程(必背)

假设有联合索引 idx(a,b,c),SQL:

sql 复制代码
select * from t where a=1 and b>2 and c like 'x%';

1)无 ICP(MySQL 5.6 前)

  1. Server 层:给存储引擎条件 a=1
  2. 存储引擎:扫描索引,找出所有 a=1 的索引项 → 全部回表拿整行。
  3. Server 层:再过滤 b>2 and c like 'x%' → 很多白回表。

2)有 ICP(默认开启)

  1. Server 层:把 a=1 and b>2 and c like 'x%' 一起下推给存储引擎。
  2. 存储引擎:遍历索引时,直接在索引上判断 a、b、c
  3. 只有全部条件满足的索引项,才去回表拿整行。
  4. 无效行在索引阶段就丢掉,不回表、不浪费 I/O

执行计划标志

EXPLAINExtra 显示:Using index condition → 正在使用 ICP。


三、生效条件(面试常问)

  1. MySQL 5.6+ ,默认开启(optimizer_switch='index_condition_pushdown=on')。
  2. 引擎:InnoDB / MyISAM(不支持全文索引)。
  3. 索引:联合索引(最左前缀匹配)。
  4. WHERE 条件:部分字段在索引里,且不是主键、不是函数/表达式。
  5. 访问类型:range / ref / eq_ref / ref_or_null

四、ICP vs 覆盖索引(区别必背)

  • 覆盖索引(Using index) :查询列全在索引里完全不回表,直接从索引拿数据。
  • 索引下推(Using index condition)必须回表 (如 select *),但尽量少回表

一句话:

  • 覆盖索引 = 不回表
  • 索引下推 = 少回表

五、优化示例(直接能用)

表:user(name, age, city),联合索引 idx_name_age_city(name,age,city)

慢 SQL(无 ICP 效果)

sql 复制代码
select * from user where name='张三' and city='北京';
  • 索引最左前缀:name='张三'
  • 无 ICP:所有 name=张三 都回表 → Server 过滤 city='北京'
  • 有 ICP:索引里有 city,直接在索引过滤 → 回表大幅减少

开启/关闭 ICP

sql 复制代码
-- 开启(默认)
set optimizer_switch='index_condition_pushdown=on';

-- 关闭(测试用)
set optimizer_switch='index_condition_pushdown=off';

六、总结(面试直接背)

  • ICP 作用:减少回表次数,降低磁盘 I/O,提升查询性能。
  • 核心原理:将索引字段的过滤条件下推到存储引擎,在索引遍历阶段过滤。
  • 生效场景:联合索引、条件字段在索引中、InnoDB/MyISAM。
  • 与覆盖索引区别:覆盖索引不回表,ICP 减少回表。

相关推荐
佛祖让我来巡山5 个月前
【面试题】MySQL 的索引下推是什么?
索引下推·mysql索引下推
Anakki2 年前
【MySQL精通之路】优化(1)-查询优化(6)-索引条件下推
数据库·mysql·icp·索引下推