MySQL 的索引下推(Index Condition Pushdown,简称 ICP)是什么?
索引下推是 MySQL 5.6 引入的一种查询优化技术,其核心目的是减少回表查询的次数,从而提升查询效率。它通过将部分 WHERE
条件的判断逻辑下推到存储引擎层,在索引扫描阶段就完成过滤,避免将大量不符合条件的数据返回给 Server 层处理。
传统查询流程 vs 索引下推流程
传统查询流程(无 ICP)
- 索引扫描:存储引擎通过二级索引(如联合索引)找到符合条件的记录主键。
- 回表查询:根据主键回表到聚簇索引中获取完整数据行。
- Server 层过滤:将完整数据行返回给 MySQL Server 层,再根据
WHERE
条件进行过滤。
问题:即使某些记录在索引中就能判断不符合条件,仍需回表查询完整数据,导致无效的 IO 操作。
索引下推流程(启用 ICP)
- 索引扫描与过滤并行:存储引擎在遍历二级索引时,直接对
WHERE
条件中能通过索引字段判断的部分进行过滤(例如联合索引中的字段)。 - 减少回表:只有满足索引条件的记录才会回表查询完整数据行。
- Server 层最终过滤:对回表后的数据行应用剩余的过滤条件(如非索引字段的条件)。
优势:减少回表次数,降低 IO 开销,提升查询性能。
适用场景与条件
- 联合索引的使用:
- 例如,对联合索引
(name, age)
查询时,WHERE name LIKE '张%' AND age = 10
。 - 存储引擎在索引扫描时直接判断
age = 10
,跳过不符合条件的记录。
- 例如,对联合索引
- 范围查询或模糊查询:
- 例如,
WHERE key_part1 > x AND key_part2 = y
或WHERE key_part1 LIKE 'abc%'
。
- 例如,
- 版本要求:
- 仅适用于 MySQL 5.6 及以上版本,且支持 InnoDB 和 MyISAM 存储引擎。
- 限制条件:
- 不能用于主键索引(聚簇索引),因为主键索引的叶子节点已包含完整数据。
WHERE
条件中的字段必须出现在索引中,否则无法下推。
示例分析
假设有一个用户表 user
,联合索引为 (name, age)
,执行以下查询:
SELECT * FROM user WHERE name LIKE '张%' AND age = 20;
无 ICP 的流程
- 存储引擎通过联合索引
(name, age)
找到所有name LIKE '张%'
的记录(如id=1,4
)。 - 回表查询
id=1
和id=4
的完整数据。 - Server 层再过滤
age = 20
,最终返回符合条件的记录。
启用 ICP 后的流程
- 存储引擎在遍历联合索引时,直接判断
age = 20
。 - 只有
age = 20
的记录(如id=1
)才会回表查询。 - Server 层无需额外过滤,直接返回结果。
索引下推的效果
- 减少回表次数:从多次回表减少到仅对符合条件的记录回表。
- 降低 IO 开销:避免读取大量无效数据行。
- 提升性能:尤其在过滤条件选择性高(如
age = 20
)时效果显著。
如何验证索引下推是否生效?
通过 EXPLAIN
命令查看执行计划的 Extra
字段:
- 无 ICP:
Using where; Using index condition
未出现。 - 启用 ICP:
Extra
字段显示Using index condition
。
示例:
EXPLAIN SELECT * FROM user WHERE name LIKE '张%' AND age = 20;
输出:
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
|----|-------------|-------|-------|---------------|----------|---------|------|------|--------------------|
| 1 | SIMPLE | user | range | index_name | index_name | 478 | NULL | 100 | Using index condition |
总结
- 索引下推的核心价值:通过在存储引擎层提前过滤数据,减少回表次数,提升查询效率。
- 适用场景:联合索引 + 范围查询/模糊查询 +
WHERE
条件字段在索引中。 - 注意事项:需 MySQL 5.6+,不适用于主键索引,且对非索引字段的条件无法下推。
THE END