MySQL 5.6+默认开启索引下推(ICP),其本质是优化器自动将WHERE中可由二级索引字段评估的条件下推至InnoDB存储引擎层过滤,减少回表I/O;生效需满足联合索引、条件含索引中非查找列(如idx_name_age上name LIKE '张%' AND age=25)、且不触发函数/全模糊等限制,EXPLAIN中Extra显示“Using index condition”即生效。

MySQL 5.6+ 默认开启索引下推,但必须满足联合索引 + 可下推条件
索引下推(ICP)不是手动调用的函数,而是一种由优化器自动触发的引擎层过滤机制。它只在 InnoDB 表、使用二级索引(非主键索引)、且 WHERE 条件中包含**索引中存在但无法用于查找的字段**时才生效。比如联合索引 idx_name_age (name, age),当查询 name LIKE '张%' AND age = 25 时:name 用于索引查找,age 就是可下推的字段 —— 它虽不能缩小扫描范围,但值已随索引项一起加载到内存,无需回表就能判断。
常见误判点:
- 单列索引无法触发 ICP(没有“后续字段”可下推)
-
LIKE以通配符开头(如name LIKE '%张')会导致整个索引失效,ICP 无从谈起 - 条件涉及函数或表达式(如
UPPER(name) = 'ZHANG')会阻止下推 - 查询字段含非索引列(如
SELECT *或SELECT description)是回表前提,但 ICP 是否起效与是否回表无关,只与 WHERE 中能否利用索引内字段过滤有关
用 EXPLAIN 验证是否命中索引下推
执行 EXPLAIN SELECT * FROM user_demo WHERE name LIKE '张%' AND age > 18;,重点看 Extra 列:
- 出现
Using index condition→ ICP 生效 - 只有
Using where→ 条件全在 Server 层过滤,未下推 - 出现
Using index→ 覆盖索引,根本不用回表,ICP 不参与
注意:type 必须是 range 或 ref 等索引访问类型;如果变成 ALL(全表扫描),ICP 自动失效。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
哪些 WHERE 条件能被下推?
下推能力取决于字段是否存在于当前使用的二级索引中,且不破坏最左前缀匹配。对联合索引 (a, b, c):
- ✅
a = 1 AND b > 10 AND c = 5:全部下推(b和c在索引中) - ✅
a LIKE 'x%' AND b = 20:b可下推 - ❌
a > 1 AND c = 3:跳过b,c无法用于查找,但因b缺失,c值未被索引项携带 → 不能下推 - ❌
b = 10 AND c = 20:未用最左列a,索引完全失效
字符串比较、数值比较、IN(限定少量值)、部分 IS NULL 都支持下推;但 OR、子查询、NOT 逻辑通常中断下推。
关闭或强制启用索引下推会影响实际性能吗?
可通过 SET optimizer_switch='index_condition_pushdown=off'; 临时关闭,但一般不建议:
- 关闭后,原本一次回表的数据可能变成多次(例如联合索引查出 100 行主键,Server 层逐个回表再过滤)
- 开启状态下,若数据分布极倾斜(如
age = 25占 99%),下推收益微乎其微,但也不会变慢 - 真正影响性能的是索引设计本身 —— 如果
age过滤性差,即使下推了,仍要回表大量记录;此时应考虑调整索引顺序,或增加过滤性强的字段到联合索引左侧
ICP 是锦上添花,不是雪中送炭。它依赖你已经建好合理联合索引,且查询条件恰好“卡”在索引结构的缝隙里 —— 那些本该被读出来、却能在引擎层当场丢弃的记录,才是它真正发力的地方。

















