Skip to content

MySQL 的索引下推是什么? ​

  • 标签:后端、MySQL、数据库

🏛 业务架构师 ​

索引下推(ICP,Index Condition Pushdown)是 MySQL 5.6 的优化:原本联合索引中未用于定位的列,要回表取回整行后再在 Server 层过滤;有了 ICP,存储引擎层先利用索引列里的值做过滤,过滤掉的数据不再回表。

业务收益用一个电商筛选例子说明:where category_id=? and status=1 and brand like '小米%',索引 (category_id, status, brand)。like 是范围条件,但 brand 值就在索引里——引擎层先过滤掉 90% 不匹配的行,回表次数从 10 万次降到 1 万次,查询耗时可能直接降一个数量级。减少的每一次回表都是一次随机 IO,也是数据库 CPU 和磁盘的真实成本。

我关注它的架构意义:这类优化让"中等规模的表+合理索引"继续扛住业务增长,推迟了上 ES、上分库分表这种重型方案的时间点——重型方案的迁移成本和团队能力要求高,能晚一年是一年。

实践提醒两点:一是 EXPLAIN 的 Extra 出现 Using index condition 说明 ICP 生效,做慢查询治理时这是判断依据;二是不要因为有了 ICP 就放任不合理的查询,索引列的顺序设计仍然是最根本的。

🏗 系统架构师 ​

索引下推(ICP,5.6 引入)是把本该在 Server 层做的索引列过滤下推到存储引擎层,在遍历二级索引时就顺手过滤,减少回表次数。

例子:联合索引 (name, age),查询 name like '张%' and age = 10。没有 ICP 时:引擎按 name 前缀扫出所有"张"姓的记录,逐条回表取整行,再由 Server 层过滤 age;开启 ICP 后:引擎在索引里就把 age != 10 的记录过滤掉,只对满足两个条件的记录回表。"张"姓如果有 10 万人、其中 age=10 只有 100 人,回表从 10 万次降到 100 次。

架构上的启发:这是典型的"计算下推到存储"思想,和 Hive/ClickHouse 的谓词下推、TiDB 的下推计算同源——把过滤逻辑推到离数据最近的地方,减少无效数据搬运。我在做分层架构时同样遵循:能在网关层拦截的不进服务,能在服务层过滤的不进 DB,能在存储引擎做的不过网络。

💻 全栈开发专家 ​

索引下推(ICP,Index Condition Pushdown,MySQL 5.6+):把本该在 Server 层做的 where 过滤"下推"到存储引擎层,直接利用索引里已有的列先过滤,减少回表次数。

sql
-- 索引 idx_name_age(name, age)
SELECT * FROM user WHERE name LIKE '张%' AND age = 10;

没有 ICP:引擎按 name 前缀找到所有"张"姓的主键 → 逐个回表取整行 → Server 层再过滤 age。有 ICP:引擎在索引里就把 age = 10 过滤掉,只有满足的行才回表。EXPLAIN 的 Extra 显示 Using index condition。

我验证效果的方式:对比 rows 估算值和回表次数,中文姓名场景下"张"姓占比高时,ICP 能把回表砍掉一大半,接口 RT 明显下降。

使用限制:只对二级索引生效、下推的列必须在索引里、子查询条件不适用。本质上它和覆盖索引是同一类优化思想:尽量让过滤发生在引擎层、减少随机回表。