索引条件下推
复合索引里除了前导列,通常还带着几列。当查询条件里另外几列也在索引中时,优化器可以把这些判断下推到存储引擎,在索引层就把不满足的行筛掉,只有真正命中的行才回表读数据。计划里会以「使用索引条件」的形式标出来。它的收益在回表代价高的场景下最明显:减少了随机读,也就减少了磁盘寻道与缓冲池压力。
基本信息
| 适用平台 | 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';计划标识读法
| 额外信息提示 | 含义 | 对应动作 |
|---|---|---|
| 使用索引条件 | 过滤已下推到索引层 | 回表次数减少,属正常优化 |
| 只用索引 | 不需要回表,索引已覆盖全部需要列 | 最理想的状态 |
| 使用临时表 | 中间结果需要物化 | 检查分组或排序是否可优化 |
| 使用文件排序 | 需要额外排序步骤 | 评估排序键与索引顺序是否匹配 |
| 全表扫描提示 | 未使用索引 | 检查条件是否与索引前缀匹配 |
下推只针对索引中已有的列:查询里还需要索引之外的列时,回表仍然会发生。把「使用索引条件」当成覆盖索引是常见误读,两者在计划里的标识完全不同。
为了下推而不断加宽索引并不划算:索引体积与维护成本同步上升,写入性能下降。判断依据应该是这条查询的执行频率与回表代价,而不是能否触发下推。