MySQL 索引下推(ICP)什么时候生效,什么时候反而更慢

举报
yd_286814013 发表于 2026/11/01 00:44:23 2026/11/01
【摘要】 索引下推(Index Condition Pushdown,ICP)是 MySQL 5.6 引入的优化,把本该在 Server 层做的条件过滤下推到存储引擎层,减少回表次数。但它不是万能开关,有些场景打开反而更慢。先说原理。没有 ICP 时,存储引擎按索引找到主键后全部回表,把整行交给 Server 层,再由 Server 层用 WHERE 里的条件过滤。有了 ICP,存储引擎在索引上就能用...

索引下推(Index Condition Pushdown,ICP)是 MySQL 5.6 引入的优化,把本该在 Server 层做的条件过滤下推到存储引擎层,减少回表次数。但它不是万能开关,有些场景打开反而更慢。

先说原理。没有 ICP 时,存储引擎按索引找到主键后全部回表,把整行交给 Server 层,再由 Server 层用 WHERE 里的条件过滤。有了 ICP,存储引擎在索引上就能用索引列做条件判断,不满足的直接跳过,不回表。所以 ICP 的收益等于「被跳过的回表率 × 单次回表成本」。

生效条件有四个,缺一不可。第一,必须是范围扫描、ref、eq_ref 或 ref_or_null 类型的访问,全表扫描用不上。第二,条件必须只涉及索引里的列,如果用到了索引外的列,存储引擎无从判断。第三,必须是 InnoDB 或 MyISAM,且优化器开关 index_condition_pushdown 是开的。第四,WHERE 条件在索引上可评估,也就是函数包裹索引列这种写法不算。

看个例子。联合索引 (a, b),查询 where a = 1 and b like '%xx%'。a 能用于索引定位,b 因为前缀模糊无法定位,但 b 在索引里,可以下推判断,只有 b 命中的行才回表。这时候 ICP 收益最大。

反过来,什么时候它反而慢。第一种,索引列的选择性极差。比如性别这种列,下推判断后仍然命中一半的行,等于白算一遍,还多了一次引擎层判断开销。第二种,索引覆盖了大部分列,回表成本本来就低,ICP 的收益抵不过判断开销。第三种,联合索引里下推的列在最右侧且数据分布倾斜,索引扫描本身就要扫很多行,ICP 只是减少了回表,扫描量没变。

怎么验证。EXPLAIN 输出里的 Extra 列出现 Using index condition,说明 ICP 生效了。对比开关前后的执行计划:

set optimizer_switch='index_condition_pushdown=off';

explain select ...;

set optimizer_switch='index_condition_pushdown=on';

explain select ...;

再用 handler_read_next 和 handler_read_rnd_next 的差值看实际回表次数,比执行时间更可靠,因为执行时间受缓存影响大。

一个常见误判:把 ICP 和覆盖索引(Using index)搞混。覆盖索引是不回表,ICP 是少回表,两者可以同时出现,Extra 里会写 Using index condition; Using index。看到只有 Using index 才是彻底不回表。

最后提醒,联合索引的列顺序决定了 ICP 能否发挥作用。把常用于范围过滤的列放在联合索引的靠前位置,让它既能用于定位又能用于下推,收益最高。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。