
ref 通常比 range 快,但不是绝对的——关键看索引结构、条件分布和是否覆盖查询。
ref 是怎么定位数据的?
ref 类型表示 MySQL 用索引做等值查找(= 或 ),直接跳到索引树中某个键值位置,然后向右线性扫描重复值。整个过程基本是“一次定位 + 小范围扫”,不涉及区间边界计算或遍历大量索引节点。
- 前提是该列有索引,且不是唯一索引(否则会是
eq_ref或const) - 例如
WHERE status = 'active',如果status有普通二级索引,就大概率走ref - 即使匹配多行,只要重复值不多(比如 10–100 行),开销仍很低
range 为什么开销更大?
range 类型要确定一个索引区间(比如 WHERE created_at BETWEEN '2025-01-01' AND '2025-06-01'),然后从左边界开始逐条遍历索引项,直到超出右边界。这个过程无法跳过中间节点,B+ 树的遍历路径更长,I/O 和 CPU 消耗都更高。
- 哪怕只查 10 行,如果范围跨度大(比如覆盖几万条索引记录),MySQL 仍需检查每一条索引项是否满足条件
-
IN列表也会被归为range,但如果列表很长(如IN (1,2,...,1000)),实际性能可能接近ref,但执行计划仍显示为range - range 不保证顺序读取物理页,缓存局部性差,容易触发更多随机 I/O
什么时候 range 反而比 ref 快?
真实场景中,ref 并非永远赢。以下情况 range 可能更优:
- ref 对应的索引列重复率极高(比如
gender只有 'M'/'F'),导致匹配几十万行,而 range 条件恰好落在稀疏区间(如id > 9999900只返回 100 行) - range 使用了覆盖索引(
Using index),而 ref 查询需要回表(Using where),此时 IO 差异起主导作用 - 优化器启用 ICP(Index Condition Pushdown),把部分
WHERE过滤下推到存储引擎层,大幅减少回表次数 - force index 强制使用复合索引时,range 可能比 ref 利用更多索引字段(如
(a,b,c)上WHERE a=1 AND b > 10,range能用上前两列,ref只用上a)
真正影响性能的从来不是 type 字段本身,而是它背后反映的索引利用效率、数据分布和执行路径。别只盯着 ref 就觉得稳了——得看 rows、key_len、Extra 里的 Using index 或 Using filesort 才算数。











