Using index仅表示覆盖索引生效、无需回表,但不保证查询高效;若WHERE含函数、不满足最左前缀、或存在无法下推的条件(如LIKE '%abc'、IS NULL、隐式转换),仍会导致全索引扫描或server层二次过滤,配合type=index、rows高、filtered低可识别此类“假高效”问题。

Using index 出现但查询仍慢,大概率不是索引没生效
看到 Using index 就以为“没问题”,这是最常见的误判。它只表示 MySQL 从索引页里直接取到了所有需要的字段(覆盖索引),不回表,但不保证 WHERE 条件真的被高效下推了。
典型陷阱:
-
WHERE用了函数,比如WHERE YEAR(create_time) = 2023→ 即使create_time有索引,type往往是index或ALL,rows高得离谱 - 复合索引是
(a, b, c),但查询写成SELECT a FROM t WHERE c = 1→ 不满足最左前缀,Using index不会出现,哪怕a和c都在索引里 -
SELECT *+ 二级索引 → 永远不会出现Using index,因为二级索引不存除索引列外的其他字段(主键除外)
Using where; Using index 的真实含义是“过滤动作分了两层”
这个组合不是 bug,而是明确告诉你:索引确实覆盖了所有 SELECT 和 WHERE 字段,但其中一部分 WHERE 条件无法由存储引擎层直接完成判断,必须由 server 层对引擎返回的每一行再筛一遍。
哪些条件会触发 server 层二次过滤?
-
LIKE '%abc'(前导通配符) -
IS NULL或IS NOT NULL(尤其当字段允许 NULL 时,InnoDB 对 NULL 的索引处理较特殊) - 隐式类型转换,比如字符串字段
status定义为VARCHAR,却写WHERE status = 1 - 部分范围条件组合,如
WHERE a = 1 AND b > 10 AND c LIKE 'x%',其中c LIKE 'x%'可能无法下推
关键观察点:filtered 列如果长期低于 30,基本可以确认 server 层干了大量无效搬运工作。
别光看 Extra,要结合 type、key_len 和 rows 一起读
Extra 是补充信息,不是全貌。单独看 Using index 或 Using where; Using index 没法判断效率好坏。
必须同步检查:
-
type是ref还是range?如果是index(全索引扫描),哪怕有Using index,实际也是扫完整个索引树 -
key_len是否符合预期?比如索引是(a, b, c),key_len显示只用了前两个字段,说明第三个字段上的条件没走索引 -
rows值是否接近表总行数?如果rows = 100000且filtered = 5,意味着引擎返回了 10 万行,server 层只留下 5000 行 —— 这就是典型的“假高效”
Using index condition 是 5.6+ 的优化项,别和 Using where; Using index 混淆
Using index condition 表示启用了 ICP(Index Condition Pushdown),即把部分 WHERE 条件“下推”到存储引擎层,在读取索引项时就做过滤,减少回表次数。它和 Using where; Using index 的根本区别在于:前者过滤发生在引擎层,后者过滤发生在 server 层。
常见触发场景:
- 查询用到二级索引,且 WHERE 中有多个条件,其中部分可下推(如等值、前缀 LIKE)、部分不可下推(如函数、NULL 判断)
-
type是ref或range,但key_len明显小于索引总长度,说明只用了索引前缀做查找,其余条件靠 ICP 过滤 - MySQL 5.5 及更早版本不会显示
Using index condition,只会退化成Using where,容易误判为没优化
真正难搞的不是 Using index 有没有,而是 WHERE 条件里哪些能进引擎、哪些被拦在 server 层 —— 这一点,光看 Extra 永远看不出全貌。


















