mysql type

type 是 EXPLAIN 里最重要字段之一(访问类型),代表 MySQL怎么去查找行,性能从最好 → 最差依次排列,后端面试高频考点,我给你完整版本、含义、例子、踩坑、面试话术(适合求职)。

⚠️口诀: system > const > eq_ref > ref > range > index > ALL

越靠左越快;目标:尽量做到 ref / range ;坚决警惕 ALL (全表扫描)

逐个详解(带示例 + 要点 + 坑)

表约定:

user(id主键, phone唯一索引, name普通索引, age无索引)

  1. system ⭐最优

表只有 1 行数据,系统表也常见。

  • 极少见到,只是理论最高等级;业务SQL几乎碰不到。

sql

EXPLAIN SELECT * FROM mysql.time_zone; --系统表经常 system

  • 注意:不是你优化出来的,是表本身就只有一条,不用刻意追求。
  1. const ⭐非常好

通过主键 / 唯一索引等值匹配,最多返回1行;查到之后这个值被当成「常量」,优化器后续直接用,不再回表扫描。

sql

EXPLAIN SELECT * FROM user WHERE id = 100; -- id主键

EXPLAIN SELECT * FROM user WHERE phone='13800138000'; -- phone唯一索引

✅特征:等值、唯一索引、最多一行

坑: where id>1 →就不是 const!const 必须是等值 =。

  1. eq_ref ⭐很好

多表 JOIN 时:被驱动表用主键 / 唯一索引去匹配,每次连接只匹配到一行。

常见: A JOIN B ON B.id = A.b_id ,B 的 id 是主键。

sql

EXPLAIN SELECT * FROM a JOIN b ON b.id = a.b_id;

-- b那一行的 type=eq_ref

区别:

  • const :单表,查一次就结束

  • eq_ref :join循环里,每一次都精准命中唯一一条

注意:普通索引不会出来 eq_ref,必须主键/唯一。

  1. ref ✅理想常用(业务优化目标之一)

使用普通二级索引等值查询,可能匹配多行。不是唯一,所以叫「引用查找」。

sql

EXPLAIN SELECT * FROM user WHERE name='张三'; -- name普通B+索引

EXPLAIN SELECT * FROM user WHERE age=20; -- 如果age建普通索引

也出现在 join:被驱动表用普通索引匹配多条。

✅日常标准:很多正常优化完的SQL就是 ref,不用非要冲到 const。

坑:ref 只是代表用到索引;不代表就快! 如果这个值命中几十万行,照样慢;要看 rows 列。

补充: ref_or_null (ref变种): where name='xxx' or name is null ,也是索引可用。

  1. range ⚠️有索引但是「范围扫描」

在索引上做范围查找: >、<、>=、<=、between、in()、or

在索引的一段区间来回扫,而不是精准一个点。

sql

EXPLAIN SELECT * FROM user WHERE id > 100;

EXPLAIN SELECT * FROM user WHERE id BETWEEN 1 AND 500;

EXPLAIN SELECT * FROM user WHERE phone IN ('a','b');

⭐超级重要考点:

一旦 type=range ,并且这个字段在联合索引里 →它就是「范围断点」!它后面的 order by 字段再也不能利用索引消除 filesort (就是上一节讲 filesort 的那个坑!)

注意: in 有时候优化器判定为 ref,有时候 range,取决于数量。

range 不是不能用;但是扫描区间太大也要警惕,看 rows 。

  1. index ⚠️「全索引扫描」!≠ 好东西!

把整个B+索引从头到尾扫一遍(索引树遍历,没有利用索引快速定位)

注意!很多人误解:type=index就是走了索引、很OK ❌

  • 和 ALL(全表)区别:

  • ALL :扫描聚簇索引(完整数据行)

  • index :扫描二级索引树;IO通常比ALL小,但依然是完整遍历索引!

两种典型场景:

  1. select name from user; name有二级索引 →覆盖索引但是没有where条件,直接把二级索引全部扫一遍(Extra:Using index)

  2. order by name ,没有where;被迫顺序扫整个索引用来排序

不要看见 type=index 就开心:它是「索引上的全表扫描」,数据量大依然灾难。

  1. ALL ❌最坏!全表扫描(Full Table Scan)

没可用索引,遍历聚簇索引全部行。就是大家常说的没走索引。

sql

EXPLAIN SELECT * FROM user WHERE age=18; -- age没建任何索引

但是有个重要理性认知:

不是看到 ALL 就必须立刻加索引!

  • 如果表只有几十行,全表扫描反而更快(索引还有回表开销),优化器会主动选择 ALL;

  • 如果表几千、几万+、QPS高 → ALL就是危险信号,必须干预。

还有几个少见扩展type(面试偶尔提到)

  • ref_or_null :ref + 还要找 NULL,例如 where name='xx' or name is null

  • unique_subquery :子查询里命中唯一索引

  • index_subquery :子查询命中普通索引

  • merge :索引合并( index_merge ,Extra会提示)多个单字段索引合并一起用;有时候是临时救急,通常不如精心设计一条联合索引

index_merge:比如 where a=1 or b=2 ,a,b各有单独索引;MySQL把两个索引结果合并;它不等于「优化完美」,很多时候代表缺少合适联合索引。

📊性能等级速查表(复制备忘)

type 等级 说明 目标?

system ✨天花板 仅单行系统表 不用追求

const ✨极好 主键/唯一索引等值,1行 能拿到当然棒

eq_ref ✅优秀 Join,主键精准单行匹配 正常

ref ✅良好 普通索引等值,多条 ✅业务最常见理想结果

range ⚠️注意 索引范围扫描 > < between in 可用,提防「范围阻断order by」

index ❗警惕 全索引扫描 尽量避免(虽然是索引但在遍历)

ALL ❌危险 全表扫描 大表必须消灭

一条记忆链条(背这个面试直接说):

system > const > eq_ref > ref > range > index > ALL

🧠面试高频问题 & 口述答案(背)

Q1: type=index 是不是代表已经很好的走索引了?

A:不是!type=index = 全索引扫描,它只是遍历二级B+树,没有利用索引快速定位;相当于"索引版全表扫描",量大依然很慢,不要和ref/range混淆。

Q2: ref 和 range 的区别?

A:ref是索引等值点查找;range是一段区间扫描;range有一个很关键副作用:在联合索引中它是范围断点,后面排序字段无法利用索引消除filesort。

Q3:是不是只要 type=ALL 我就要马上加索引?

A:不一定,如果表很小(几十行),优化器认为全表扫描成本更低;但是大表、高频查询出现ALL就必须优化;同时还要配合看 rows 、 key 、 Extra(Using filesort/Using temporary) 一起判断,不能单拿type一个字段下定论。

Q4:index_merge是什么?好不好?

A:是索引合并,多个独立索引分别查找再合并;它有时是优化器妥协方案,多数场景一条设计良好联合索引性能会优于index_merge。

✅配套看Explain其他列(和type联动)

不要只看type!要组合判断:

  • key :真正被选用的索引名字(null=没选)

  • key_len :这次索引用到多少字节(用来判断联合索引用了几列!超级实用调参工具)

  • rows :预估扫描行数(type再好,如果rows几十万也要小心)

  • Extra :有没有 Using filesort / Using temporary

如果你需要,我可以给你: key_len怎么计算 + 几个「同一条SQL,改索引→type从ALL→ref→range变化的演示案例」;或者一份Explain完整字段速查表。

相关推荐
花卷持续成长1 小时前
慢SQL的整体优化思路
后端·mysql
鱼很腾apoc2 小时前
【MySQL】第3期 索引、事务与视图系统详解
linux·mysql·事务·索引·dml·视图·macc
misty youth3 小时前
Navicat与PHPstudy小皮
mysql·adb·php·navicat
毕业设计7034 小时前
(免费领源码)SSM董家湾线上点餐系统04682- java、PHP、python、C#、小程序、大数据、单片机、网络工程等)
java·redis·mysql·tomcat·maven·mybatis·ssm
leaf9z4 小时前
阿里云rds查看所有库大小
mysql·阿里云
Yyyyyy~4 小时前
【Mysql】表的操作
数据库·mysql
Q26433650234 小时前
【有源码】基于SpringBoot+Vue的居民健康体检与慢病干预管理系统-面向智慧医疗的体检预约与健康知识服务平台
java·vue.js·spring boot·mysql·毕业设计·javaweb·课程设计
要开心吖ZSH5 小时前
《通过SeaTunnel 把 MySQL 的数据搬进 Doris》番外篇:容量、切分与速度——Doris 能扛多少,比 MySQL 快多少
mysql·性能优化·doris·分区·分表·分桶
曦夜日长6 小时前
MySQL系统篇,数据库基础(二):数据库概念、SQL 分类与存储引擎
数据库·sql·mysql