Loose Index Scan拒绝范围查询,因其依赖索引中GROUP BY列值天然连续分块以实现跳跃读取;一旦WHERE含>、<、BETWEEN等范围条件,分组值在索引中变得离散,无法跳转,被迫退化为Tight Index Scan。

Loose Index Scan 为什么拒绝范围查询
MySQL 的 Loose Index Scan(松散索引扫描)本质是“跳着读索引”:它只取每个分组值在索引中的第一个位置,然后直接跳到下一个不同分组值的起始位置,不逐行遍历。这种跳跃能力依赖一个前提:索引中 group by 列的值天然连续且可预测地分块。
一旦 WHERE 中出现范围条件(比如 c2 > 100、c3 BETWEEN '2024-01-01' AND '2025-01-01' 或 c4 LIKE 'abc%'),索引的有序性就被局部打乱了——你无法再靠“下一个不同 c1 值在哪”来跳转,因为满足范围的 c1 可能分散在多个不相邻的索引片段里。
此时 MySQL 必须退化为 Tight Index Scan(紧凑索引扫描),也就是老老实实按顺序扫完所有符合范围条件的索引行,再从中提取分组键。这会显著增加 rows 和 I/O,执行计划的 Extra 字段也不会再显示 Using index for group-by。
哪些范围操作会触发退化
不是所有带比较符的条件都等价。以下操作会直接让 Loose Index Scan 失效:
-
>、<、>=、<=、BETWEEN -
LIKE前缀匹配以外的形式(如LIKE '%abc'或LIKE '%abc%') -
IN虽然语法像等值,但如果右侧是大量值(如IN (1,2,...,1000)),优化器可能估算成本后主动放弃 Loose 扫描 - 即使范围列不在
GROUP BY中,只要它属于同一组合索引且出现在WHERE里,也会中断 Loose 扫描路径
等值条件才是 Loose 扫描的通行证
只有这些条件能让 MySQL 继续“跳着走”:
-
=、IS NULL、IN(小集合,且优化器判定为等价语义) - 条件必须作用于索引的前导列或紧邻前缀列,例如索引是
(a, b, c),那么WHERE a = 1 AND b = 2是安全的;但WHERE a = 1 AND c = 3就不行(b缺失,c无法跳过)
还要注意:如果索引定义本身是前缀索引(如 INDEX(name(10))),哪怕写的是等值条件,Loose Index Scan 也完全不可用——因为索引值不完整,MySQL 无法确认分组边界。
如何验证是否真的用了 Loose Index Scan
别信猜测,看 EXPLAIN 输出:
-
type字段通常是range(不是ALL或index) -
key显示实际使用的索引名 - 最关键的是
Extra字段必须包含Using index for group-by
如果看到 Using temporary 或 Using filesort,说明 Loose 扫描已彻底失效,MySQL 正在建临时表做分组——这时就得回头检查 WHERE 是否混入了范围条件、索引列顺序是否错位、或者聚合函数是否违规用了 SUM/COUNT 等非允许函数。
真正容易被忽略的点是:范围条件和 GROUP BY 列哪怕不在同一字段,只要共享一个组合索引,就足以破坏 Loose 扫描的前提。这不是 bug,是设计使然——松散扫描要的不是“有索引”,而是“索引分组结构未被扰动”。


















