MySQL 索引条件下推是什么?Using index condition 并不是覆盖索引

MySQL 索引条件下推是什么?Using index condition 并不是覆盖索引

EXPLAIN 里看到 Using index condition,很多人会顺手说一句「走了覆盖索引」。这两个不是一回事。

索引条件下推,英文是 Index Condition Pushdown,简称 ICP。它做的事没那么玄:二级索引已经拿在手里时,能在索引条目上判断的条件,就别急着回表。

看一个接近面试题的表:

sql 复制代码
CREATE TABLE people (
  id BIGINT PRIMARY KEY,
  zipcode CHAR(5) NOT NULL,
  lastname VARCHAR(64) NOT NULL,
  firstname VARCHAR(64) NOT NULL,
  address VARCHAR(255) NOT NULL,
  KEY idx_zip_last_first (zipcode, lastname, firstname)
) ENGINE=InnoDB;

现在要找邮编是 95054、姓氏里带 etrunia、住址又带 Main Street 的人:

sql 复制代码
SELECT *
FROM people
WHERE zipcode = '95054'
  AND lastname LIKE '%etrunia%'
  AND address LIKE '%Main Street%';

zipcode 是联合索引第一列,MySQL 可以据此定位扫描范围。

lastname LIKE '%etrunia%' 前面有通配符,不能继续缩小 B+Tree 的扫描范围。这里很容易误会成这个条件彻底没用。不是,它虽然不能决定从哪一条索引记录开始扫,却可以在索引条目里被判断。

没有 ICP 时,存储引擎拿到一个 zipcode='95054' 的索引条目,就去二级索引外找到整行,再把 lastnameaddress 条件交给 MySQL Server 判断。候选多的时候,回表会白跑很多趟。

开着 ICP,流程变成这样:

text 复制代码
扫描 idx_zip_last_first 中 zipcode = '95054' 的条目
  └─ 先在条目里判断 lastname LIKE '%etrunia%'
       ├─ 不满足:跳过,不读整行
       └─ 满足:回表,继续判断 address LIKE '%Main Street%'

所以它省的是「无效候选的整行读取」,不是让原本不能走索引的条件突然变成范围查询。

为什么它和覆盖索引不是一回事

覆盖索引是查询要的列都在索引里,根本不需要读整行。常见的 EXPLAIN 信号是 Using index

ICP 的前提恰好往往是还要读完整行。上面的 SELECT *address 都不在 idx_zip_last_first 里,匹配了 lastname 以后仍然要回表。它只是把回表的时机往后推。

MySQL 官方手册对此写得很直白:ICP 命中时,Extra 会出现 Using index condition;这不表示 Using index。一个是先过滤再回表,一个是不回表。

面试里别漏掉这两个边界

ICP 不是所有索引扫描都有收益。

对 InnoDB 来说,它只用于二级索引。聚簇索引叶子节点本身就带完整行,已经读到整行了,再下推也省不掉这次 I/O。

它也不是万能的 WHERE 下推。只有能用索引列计算的那部分条件才有机会下推;子查询、存储函数等条件就不在这个范围里。MySQL 8.4 手册还列出了虚拟生成列二级索引不支持 ICP 这个边界。

我排查时会把它当成一个结果信号,不会为了凑 Using index condition 重建索引。先看查询返回多少行、扫描多少候选、回表是不是主要成本,才知道这个优化值不值。

怎么验证

同一条 SQL 可以在会话里临时关掉 ICP 对比:

sql 复制代码
SET SESSION optimizer_switch = 'index_condition_pushdown=off';
EXPLAIN ANALYZE
SELECT *
FROM people
WHERE zipcode = '95054'
  AND lastname LIKE '%etrunia%'
  AND address LIKE '%Main Street%';

SET SESSION optimizer_switch = 'index_condition_pushdown=on';

别只盯执行时间。数据量小、全在 Buffer Pool 里时,差异可能并不明显。更有用的是结合 EXPLAIN ANALYZE 看扫描与实际返回的行数,再看业务查询的延迟和读 I/O。

面试被问到「联合索引里中间列用了前缀模糊匹配,后面的列还有没有意义」,别直接答「索引失效」。可以先说它不能继续缩小范围,再补一句:如果这个条件所需列仍在二级索引里,ICP 可能先过滤一轮,少回一些表。

相关推荐
瀚高PG实验室9 小时前
使用pg_stat_statements抓取数据库TOP SQL
数据库·sql·postgresql·瀚高数据库
这个DBA有点耶11 小时前
非关系型数据库到底有几种?键值、文档、列族、图,一篇讲透
mysql·架构·nosql
企业数字化笔记12 小时前
固定资产财务账与实物账怎么对账?折旧快照、差异检测与SQL核对
android·数据库·sql
jyOverQ12 小时前
MySQL 事务到底是什么?ACID 四大特性与隔离级别怎么理解?
数据库·mysql
IT大白鼠14 小时前
MySQL 分布式集群系列 · 第八篇(收官)——NDB 集群面试高频题 +架构总结与未来演进
分布式·mysql·面试
IT大白鼠14 小时前
MySQL 分布式集群系列 · 第七篇——生产调优实战:NDB 性能、内存、高可用全方位优化
数据库·分布式·mysql
ShineWinsu14 小时前
对于MySQL:内置函数的解析
linux·数据库·c++·mysql·面试·函数·查询
TDengine (老段)17 小时前
TDgpt 使用 — 部署、SQL、算法
大数据·数据库·sql·算法·时序数据库·tdengine·涛思数据
邪修king19 小时前
MySQL数据库(二):操作详解:从创建、查看到备份恢复
数据库·mysql
邪修king20 小时前
MySQL 数据库(三):表级操作实战:增删查改全实例演示 + 企业实操红线规范
android·数据库·mysql