索引下推有什么用?MySQL里这个小技巧真能省不少事

你有没有遇到过这样的场景:查用户订单,条件是 status = 'shipped'create_time > '2024-01-01',表有上千万行,但只加了 status 字段的单列索引——结果查询还是慢?明明走了索引,为啥还要回表过滤一堆数据?

索引下推,就是让“筛选动作”提前到索引扫描阶段

在 MySQL 5.6 之后,默认开启 Index Condition Pushdown(ICP),也就是常说的“索引下推”。它不改变索引结构,而是改变了执行流程:

以前:存储引擎按索引顺序读出主键(或聚簇索引记录),把整行数据返回给 Server 层,Server 层再判断 create_time > '2024-01-01' 是否成立。

现在(开启 ICP 后):只要索引里包含 create_time(比如联合索引 (status, create_time)),存储引擎在读索引项时就顺手把 create_time 的值拿出来比一比。不满足的记录,压根不取整行,直接跳过。

举个实际例子

假设有一张订单表:

CREATE TABLE `orders` (
  `id` BIGINT PRIMARY KEY,
  `user_id` INT,
  `status` VARCHAR(20),
  `create_time` DATETIME,
  INDEX idx_status_ctime (`status`, `create_time`)
);

执行查询:

SELECT * FROM orders 
WHERE status = 'shipped' AND create_time > '2024-03-01';

有 ICP 时,InnoDB 扫描 idx_status_ctime 索引,遇到 status='shipped'create_time='2024-02-15' 的索引项,当场丢弃,不回表;没 ICP 时,得先把对应主键查出来、再回聚簇索引捞整行、最后 Server 层才过滤掉——多一次磁盘 IO,也多一次内存拷贝。

实测中,当过滤条件能筛掉 80% 以上索引项时,ICP 常常让查询快 2–3 倍,尤其对 SSD 延迟敏感的线上服务,效果更明显。

它不是万能的,但很实在

ICP 只作用于 二级索引,且要求索引中包含 WHERE 条件里的字段(至少部分)。像 ORDER BYGROUP BYHAVING 中的字段不参与下推;函数操作如 YEAR(create_time) = 2024 也会让 ICP 失效。不过日常写查询时,只要习惯建好覆盖度高的联合索引,ICP 就在默默帮你省资源。

就像快递分拣站——以前是把所有标着“上海”的包裹全拉到总仓,再挨个看门牌号;现在扫描面单时就顺手把“非浦东新区”的挑出去,剩下才是真正要送的。活儿没少干,但车少跑两趟,人也轻松点。