eq_ref出现在被驱动表关联字段为PRIMARY KEY或UNIQUE INDEX且使用等值匹配(=)的JOIN场景下,表示对驱动表每行最多查被驱动表1行,实现1:1映射。

eq_ref 出现在什么 JOIN 场景下
当被驱动表的关联字段是 PRIMARY KEY 或 UNIQUE INDEX,且查询条件为等值匹配(=)时,type 就是 eq_ref。它意味着对驱动表的每一行,MySQL 最多只需查一次被驱动表——因为索引键值唯一,结果行数确定为 0 或 1。
常见于:两表用主键互连、或主键连唯一索引列;例如 SELECT * FROM orders o JOIN users u ON o.user_id = u.id,其中 u.id 是主键,o.user_id 有普通索引或无索引(不影响 u 表的访问类型)。
- 驱动表可以是任意顺序,只要被驱动表走的是唯一索引,就可能是
eq_ref -
eq_ref不要求驱动表本身有索引,但若驱动表没索引,它自己可能走ALL,拖慢整体性能 - 如果被驱动表的关联字段允许
NULL,即使定义了唯一索引,也可能退化为ref(因NULL不参与唯一约束校验)
ref 和 eq_ref 的关键区别在索引唯一性
ref 和 eq_ref 都表示“使用非主键/非唯一索引做等值查找”,但核心差异就在被驱动表索引是否唯一:
-
eq_ref→ 被驱动表索引是UNIQUE或PRIMARY KEY,每键最多对应 1 行 -
ref→ 被驱动表索引是普通INDEX(非唯一),每键可能对应 N 行,MySQL 必须扫描所有匹配项 - 两者都依赖驱动表输出的值作为查找输入,但
ref的内部循环更重:对驱动表一行,可能要遍历被驱动表多行才能收齐结果
举例:users 表上 email 列建了普通索引(非唯一),执行 JOIN user_logs l ON u.email = l.email,l 表的访问类型就是 ref;而如果 l.email 加了 UNIQUE 约束,就变成 eq_ref。
为什么有时候明明用了主键,EXPLAIN 却显示 ref 而不是 eq_ref
这不是 MySQL 判错,而是你看到的“主键”未必是被驱动表实际使用的索引,或者索引失效了:
- 被驱动表用了联合索引,但 WHERE 条件没覆盖最左前缀,导致索引部分失效,降级为
ref - 关联字段存在隐式类型转换,比如
INT列和字符串常量比较(ON u.id = '123'),导致索引无法用于唯一性判断,只能走ref - 被驱动表是
LEFT JOIN的右表,但关联字段允许NULL,且该字段上的唯一索引未声明NOT NULL,MySQL 会保守地按ref处理 - 优化器认为统计信息不准,误判索引选择性,强制改用非唯一路径(少见,但可通过
ANALYZE TABLE更新统计信息缓解)
ref 和 eq_ref 对查询性能的实际影响
差别不在单次查找快慢,而在被驱动表的「扫描放大倍数」:
-
eq_ref:驱动表 N 行 → 被驱动表最多查 N 行(1:1 映射) -
ref:驱动表 N 行 × 平均匹配 M 行 → 被驱动表查约 N×M 行(M > 1 时显著放大) - 若 M 达到几十甚至上百(比如日志表中某用户 ID 出现频次极高),
ref可能比eq_ref慢一个数量级
真正要注意的,不是 type 字段写着什么,而是看 rows 估算值和 key 实际使用的索引是否符合预期。有时候 eq_ref 搭配 rows=10000(驱动表全扫),比 ref 搭配 rows=100(驱动表已过滤)还慢。



















