首页/数据/SQL 速查/索引条件下推 ICP
性能与执行计划72 条

索引条件下推 ICP

MySQL 5.6+ 把部分 WHERE 条件下推到存储引擎、在索引层先过滤(Extra: Using index condition),减少回表次数。

SQL 速查数据更新于 2026-10-13

索引条件下推

复合索引里除了前导列,通常还带着几列。当查询条件里另外几列也在索引中时,优化器可以把这些判断下推到存储引擎,在索引层就把不满足的行筛掉,只有真正命中的行才回表读数据。计划里会以「使用索引条件」的形式标出来。它的收益在回表代价高的场景下最明显:减少了随机读,也就减少了磁盘寻道与缓冲池压力。

基本信息

适用平台MySQL 8.0(InnoDB 等支持该优化的引擎)
触发条件过滤列包含在所用的索引中
计划标识额外信息列出现使用索引条件的提示
收益不满足条件的行在索引层被筛掉,减少回表
代价读取索引条目本身有少量额外开销

典型使用场景

  • 复合索引的第三列参与过滤:确认过滤是否下推到了索引层
  • 大表按范围过滤:减少回表次数能显著降低耗时
  • 评估索引列顺序:判断把过滤列加进索引是否值得
  • 排查「走了索引但还是慢」:确认是否仍是大量回表
  • 对比开关前后的计划差异,理解优化的实际作用

触发与观察

触发与观察
-- 建立包含过滤列的复合索引
ALTER TABLE orders ADD INDEX idx_user_status_created (user_id, status, created_at);

-- 执行计划里应能看到条件已下推的提示
EXPLAIN SELECT * FROM orders
WHERE user_id = 100 AND status LIKE 'p%' AND created_at > '2024-01-01';
-- 额外信息列出现「使用索引条件」即表示已下推
-- 索引先用 user_id 定位,再用索引中的另外两列过滤,最后才对命中行回表

-- 确认优化开关的当前状态
SELECT @@optimizer_switch;

-- 需要对比时可按会话关闭该优化,观察计划变化(仅用于验证)
SET SESSION optimizer_switch = 'index_condition_pushdown=off';
SET SESSION optimizer_switch = 'index_condition_pushdown=on';

计划标识读法

额外信息提示含义对应动作
使用索引条件过滤已下推到索引层回表次数减少,属正常优化
只用索引不需要回表,索引已覆盖全部需要列最理想的状态
使用临时表中间结果需要物化检查分组或排序是否可优化
使用文件排序需要额外排序步骤评估排序键与索引顺序是否匹配
全表扫描提示未使用索引检查条件是否与索引前缀匹配
下推只针对索引中已有的列:查询里还需要索引之外的列时,回表仍然会发生。把「使用索引条件」当成覆盖索引是常见误读,两者在计划里的标识完全不同。
为了下推而不断加宽索引并不划算:索引体积与维护成本同步上升,写入性能下降。判断依据应该是这条查询的执行频率与回表代价,而不是能否触发下推。

易错点

  • 把「使用索引条件」当成覆盖索引,误以为不会回表,容量评估与耗时预期全部偏乐观
  • 为触发下推盲目加宽索引,写入性能下降,收益却有限
  • 在线上直接关闭优化开关做对比,导致大批查询计划退化
  • 只看计划标识不看实际耗时:下推带来额外索引读取,个别场景反而更慢
  • 过滤列顺序与索引列顺序不匹配,下推无法生效却以为已经生效

数据来源与参考

  • MySQL 8.0 Reference Manual §8.2.1.6 Index Condition Pushdown Optimization
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌