type为range表示mysql正用索引做范围扫描,常见触发条件包括between、>、=、

type 为 range 表示 MySQL 正在用索引做范围扫描,不是全表扫,也不是等值查,而是“取一段”——只要条件能走索引且带范围语义,就很可能落到这个类型。
哪些 WHERE 条件会触发 type=range
关键不在语法形式,而在是否满足「索引列 + 范围操作符 + 可下推的边界」。常见组合包括:
-
BETWEEN ... AND ...(如WHERE create_time BETWEEN '2025-01-01' AND '2025-12-31') -
>=、、<code>>、单边条件(如 <code>WHERE age > 18) -
IN后跟常量列表(如WHERE status IN (1,2,3)),但仅当该列有索引且优化器未转成index_merge时才稳定为range -
LIKE前缀匹配且索引可用(如WHERE name LIKE '张%',但WHERE name LIKE '%张'不行)
注意:!= 或 一般不会走 range,而可能退化为 index 或 ALL;IS NULL 单独出现通常是 ref_or_null,不是 range。
为什么明明建了索引,EXPLAIN 却没显示 range
常见原因不是索引没建,而是查询条件破坏了索引的有序性或可下推性:
- 对索引列用了函数或表达式,比如
WHERE YEAR(create_time) = 2025→ 索引失效,type 变成ALL - 联合索引中,范围条件出现在非最左前缀位置,例如索引是
(a,b,c),但写成WHERE a = 1 AND c > 10→c无法用上范围扫描,type 往往是ref - 字符串字段用了错误的 collation 或隐式类型转换,比如
WHERE mobile = 13800138000(mobile 是VARCHAR)→ 可能触发全表扫 - 优化器估算代价后主动放弃索引,比如表很小或范围过大(如
age > 0),它可能觉得全表扫更快
range 和 index、ALL 的性能差距有多大
三者实际 I/O 和 CPU 开销差异明显,不能只看“都用了索引”:
-
range:只遍历索引 B+ 树中满足条件的叶子节点区间,rows字段基本可信,通常毫秒级 -
index:要完整扫描整个索引(哪怕只查索引列),rows= 索引总行数,I/O 放大明显,尤其数据量大时 -
ALL:全表扫描,不仅读索引,还要回表或读聚簇索引页,rows经常严重低估,容易拖垮并发
举个例子:一张 100 万行的订单表,status 有普通索引,WHERE status IN (1,2) 是 range;但 WHERE status != 0 很可能变成 index,甚至 ALL —— 因为优化器发现要跳过太多值,不如直接扫全表。
如何确认 range 是否真的高效
光看 type=range 不够,必须结合 key、rows、filtered 和实际执行时间判断:
- 检查
key是否是你期望的索引名,避免走错索引 -
rows值是否远小于表总行数?如果rows=950000,那这个range几乎等于全扫 -
filtered值偏低(比如 - 用
SELECT SQL_NO_CACHE ...实测耗时,比 EXPLAIN 更真实;加PROFILE可看各阶段耗时分布
最容易被忽略的是:range 扫描本身不慢,但若后面跟着大量回表(比如 SELECT * 且索引不覆盖),性能瓶颈会立刻转移到主键查找和磁盘随机 IO 上。











