type 访问类型是什么
type 列描述每张表的访问方式,大致从好到差是 system、const、eq_ref、ref、range、index、ALL。const 是通过主键或唯一索引与常量比较、最多匹配一行;eq_ref 出现在连接里,被驱动表每行最多匹配一行;ref 是非唯一索引的等值查找;range 是索引范围扫描,常见于 BETWEEN、大于小于与 IN;index 表示遍历整棵索引树;ALL 是全表扫描。要特别记住:index 并不代表优化到位,它扫描整棵索引,代价已接近全表扫描。
基本信息
| const | 主键或唯一索引与常量比较,至多一行 |
|---|---|
| eq_ref | 连接时被驱动表用唯一索引等值匹配,每行至多一行 |
| ref | 非唯一索引等值查找,可匹配多行 |
| range | 索引范围扫描:BETWEEN、大于小于、IN |
| index | 遍历整棵索引树,代价接近全表扫描 |
| ALL | 全表扫描,通常是索引缺失或条件不符合索引 |
典型使用场景
- 判断查询退化:看到 ALL 就该检查条件与索引
- 验证索引生效:改写法或加索引后确认 type 提升
- 排查 type=index 的伪优化:确认过滤是否真在索引层完成
- 对比两条 SQL 的优劣:同数据量下比较访问类型
- 评估 IN 与 OR 改写效果:range 与 ALL 的差异很明显
- 确认连接方式:eq_ref 与 ref 反映被驱动表的匹配效率
示例
示例
EXPLAIN SELECT * FROM users WHERE id = 1; # const(主键等值)
EXPLAIN SELECT * FROM users WHERE email = 'a@x.com'; # ref(email 非唯一索引)
EXPLAIN SELECT * FROM orders WHERE total BETWEEN 10 AND 20; # range(total 有索引)
-- 连接场景
EXPLAIN SELECT o.id, u.name
FROM orders o JOIN users u ON u.id = o.user_id; # 被驱动表通常为 eq_ref
-- 未被索引的条件
EXPLAIN SELECT * FROM orders WHERE DATE(created_at) = '2024-01-01'; # 常见 ALL常见 type 取值
| type | 含义 | 典型场景 |
|---|---|---|
| const | 至多匹配一行 | WHERE id = 常量 |
| eq_ref | 连接时被驱动表每行至多匹配一行 | 用主键或唯一索引做连接键 |
| ref | 非唯一索引等值查找,可匹配多行 | 普通索引列等于常量或连接键 |
| range | 索引范围扫描 | BETWEEN、>、<、IN 作用于索引列 |
| index | 遍历整棵索引树 | 需要按索引顺序全读,或覆盖索引查询 |
| ALL | 全表扫描 | 没有可用索引或优化器判断扫描更划算 |
type=index 出现在输出里不代表已经优化到位:它是扫描整棵索引,代价接近全表扫描,需要继续看 key_len 与 Extra 判断过滤发生在哪一层。
eq_ref 只出现在连接场景:单表按唯一键查询会显示 const,比对计划时不要把两者场景弄混。
优化器会选择成本最低的方案,有时全表扫描确实比走索引更快(例如结果集占比很高);type 为 ALL 不必然是 bug,但需要解释清楚原因。
判断要点
- 先从是否有 ALL 开始逐行检查
- 再看 key 是否非空,确认索引真的被选中
- 结合 rows 判断扫描量是否与预期匹配
- 看 Extra 判断过滤位置:Using index 好,Using filesort 需关注
- 对比改前改后计划,作为优化是否生效的证据
- 记录典型查询的基线计划,回归时便于快速比对