Using index condition说明ICP生效,即MySQL将部分WHERE条件下推至存储引擎层在索引扫描时直接过滤,减少回表次数、磁盘I/O和Server层处理压力。

为什么EXPLAIN里看到Using index condition就说明性能变好了
它代表 MySQL 把部分 WHERE 条件直接塞进索引扫描过程,而不是等回表后再判断。比如联合索引 (city, age) 上执行 WHERE city = '杭州' AND age > 20,没 ICP 时:存储引擎只按 city 找出所有“杭州”的记录(可能几千行),全都要回表取完整数据,再由 Server 层逐条判断 age > 20;开了 ICP 后:存储引擎在读索引叶子节点时,顺手就把 age 值拿出来比一下,不满足的直接跳过,只对真正可能命中的几条做回表。
实际影响是:
– 回表次数大幅下降(从几百次降到几十次)
– 磁盘 I/O 减少(不用读那么多无关的聚簇索引页)
– Server 层 CPU 和内存压力降低(不用处理大量中间结果)
index_condition_pushdown开关怎么查和调
ICP 默认开启,但可能被全局或会话级关闭。确认方式只有这一种:
SHOW VARIABLES LIKE 'optimizer_switch';
输出中找 index_condition_pushdown=on。如果为 off,可用以下任一方式打开:
- 会话级(当前连接生效):
SET optimizer_switch='index_condition_pushdown=on'; - 全局级(需 SUPER 权限,重启后失效):
SET GLOBAL optimizer_switch='index_condition_pushdown=on'; - 永久生效要改配置文件
my.cnf,在[mysqld]下加一行:optimizer_switch="index_condition_pushdown=on"
注意:optimizer_switch 是个逗号分隔字符串,修改时别覆盖其他开关(如 materialization、semijoin)。
哪些 WHERE 条件能被下推,哪些不能
能下推的条件必须满足两个硬性前提:
- 涉及的列必须全部包含在当前使用的索引中(哪怕不是最左前缀)
- 不能有函数包装、类型转换、或跨列计算(比如
age + 1 > 21或UPPER(name) = 'ABC')
典型可下推场景:
– 等值 + 范围:索引 (a,b),WHERE a = 1 AND b > 10
– 多范围:索引 (a,b,c),WHERE a = 1 AND b > 5 AND c LIKE 'x%'
– 前缀匹配:索引 (name),WHERE name LIKE 'zhang%'
典型不可下推场景:
– WHERE a = 1 AND b + 1 > 10(表达式)
– WHERE a = 1 AND JSON_EXTRACT(data, '$.field') = 'val'(函数)
– WHERE a = 1 AND c > 100(c 不在索引里)
为什么有时候明明符合条件却没触发 ICP
常见原因不是配置问题,而是执行计划本身绕过了索引使用:
- 优化器认为全表扫描更快(比如表很小,或统计信息不准导致误判)
- 查询用了覆盖索引(
SELECT a,b FROM t WHERE a=1 AND b>2,索引(a,b)已含全部字段),根本不需要回表,ICP 就没意义了 - 索引选择错误:比如有多个索引,优化器选了单列索引
(a)而不是联合索引(a,b),那b条件自然无法下推 - 使用了
FORCE INDEX但指定的索引不包含后续过滤列
真正要验证 ICP 是否起效,唯一可靠方式是看 EXPLAIN 的 Extra 列是否出现 Using index condition —— 其他任何推测都容易误判。



















