优化命令说明
- id
- select_type
- table
- partitions
- type
- possible_keys
- key
- key_len
- ref
- rows
- Extra
解释意思:
- id
SELECT查询的标识符, 每个SELECT语句都会自动分配一个唯一的标识符
- select_type
每个select查询字句的类型,具体类型以及对应作用如下表:
| 类型名 | 解释 |
|---|---|
| SIMPLE | 简单SELECT,不使用UNION或子查询等 |
| PRIMARY | 查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY |
| UNION | UNION中的第二个或后面的SELECT语句 |
| DEPENDENT UNION | UNION中的第二个或后面的SELECT语句,取决于外面的查询 |
| UNION RESULT | UNION的结果 |
| SUBQUERY | 子查询中的第一个SELECT |
| DEPENDENT SUBQUERY | 子查询中的第一个SELECT,取决于外面的查询 |
| DERIVED | 派生表的SELECT, FROM子句的子查询 |
| UNCACHEABLE SUBQUERY | 一个子查询的结果不能被缓存,必须重新评估外链接的第一行 |
- table
显示这一行的数据是查哪张表的,不过有时短路显示的不是真实的表名。
- partitions
匹配的分区(这个目前用处不大)
- type
访问类型,表示MySQL在表中找到所需行的方式,对应的值和解释如下:
| 类型名 | 优级别 | 解释 |
|---|---|---|
| system | 1 | 表仅有一行 |
| const | 2 | 表最多有一个匹配行,在查询开始时即被读取 |
| eq_ref | 3 | 使用primary key或者unique key作为多表连接的条件,仅从该表中读取一行 |
| ref | 4 | 作为查询条件的索引在每个表匹配索引值的行从表中读取出来 |
| fulltext | 5 | 全文索引检索 |
| ref_or_null | 6 | 和ref一致,但增加了NULL值查询支持 |
| index_merge | 7 | 表示使用了索引合并优化方法 |
| unique_subquery | 8 | 使用了替换了in子查询 |
| index_subquery | 9 | 使用了替换了in子查询,但只适用于子查询中的非唯一索引 |
| range | 10 | 只检索给定范围的行,使用一个索引来选择行 |
| index | 11 | 全表扫描,但扫描表的方式是按索引的次序进行 |
| ALL | 12 | 全表扫描的方式找到匹配的行 |
type作为访问类型,其值代表着当前查询所用的类型,是体现性能的一个重要指标,从表中可以看到,从上到下,扫描表的方式越来越宽,性能也就越来越差,因此,对于一个查询,最好能保持在range级别以上。
- possible_keys
主动指出查询能用哪个索引在表中找到记录
也就是会列出在查询中的字段中有索引的字段,但不一定被查询所用。
- key
显示再查询中实际使用的索引/键,如果没有索引,则显示NULL。
但如果想强制查询中使用或忽视possible_keys列中的索引,则可以在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
- key_len
表示索引中使用的字节数。
- ref
表示哪些列或常量被用于查找索引列上的值。
- rows
显示当前查询估算到的查找到匹配记录所需的记录行数。
- Extra
显示当前查询所用的解决方式,它有以下几种情况:
| 类型名 | 解释 |
|---|---|
| Using where | 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的, |
| Using temporary | 表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询 |
| Using filesort | MySQL中无法利用索引完成的排序操作称为“文件排序” |
| Using join buffer | 改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。 |
| Impossible where | 这个值强调了where语句会导致没有符合条件的行。 |
| Select tables optimized away | 这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行 |
好问题!type 和 Extra 是 EXPLAIN 里最重要的两列,但它们描述的是不同维度的事情:
type→ 数据怎么找到的(访问类型,性能从好到坏排列)Extra→ 找到数据后做了什么额外操作
下面我按性能从最优到最差给你完整梳理一遍。
一、type 列所有选项(从好到坏)
| type | 含义 | 出现场景 |
|---|---|---|
| system | 表只有一行(系统表) | MyISAM/Memory 引擎的特殊情况,几乎见不到 |
| const | 最多匹配一行,通过主键/唯一索引等值查询 | WHERE id = 1 |
| eq_ref | 多表 JOIN 时,被驱动表通过主键/唯一索引关联 | JOIN ... ON t2.id = t1.t2_id |
| ref | 非唯一索引等值查询,返回多行 | WHERE test = 1(test 是普通索引) |
| fulltext | 使用全文索引 | MATCH(col) AGAINST(...) |
| ref_or_null | ref 的变体,额外搜索 NULL 值 | WHERE col = 1 OR col IS NULL |
| index_merge | 多个索引合并(Intersection/Union) | WHERE a = 1 OR b = 2(a、b 各有索引) |
| unique_subquery | IN 子查询中命中唯一索引 | WHERE id IN (SELECT id FROM t2) |
| index_subquery | IN 子查询中命中普通索引 | 同上但子查询无唯一索引 |
| range | 索引范围扫描 | WHERE id > 10、IN、BETWEEN、LIKE 'abc%' |
| index | 全索引扫描(扫描整个索引树) | 覆盖索引但无 WHERE 条件,或 ORDER BY 主键 |
| ALL | 全表扫描 | 没有任何索引可用,或优化器认为全表更快 |
📌 日常开发中你需要重点关注的:
const→ref→range→index→ALL
二、Extra 列常见选项
| Extra | 含义 | 好坏 |
|---|---|---|
| Using index | 覆盖索引,只扫描索引不回表 | ✅ 最优 |
| Using where | 存储引擎返回后,Server 层额外过滤 | ⚠️ 正常但需关注 |
| Using index condition | 索引下推(ICP),在存储引擎层用索引过滤 | ✅ 好特性 |
| Using filesort | 需要额外排序 | ❌ 大数据量时需优化 |
| Using temporary | 使用了临时表(通常伴随 GROUP BY / DISTINCT) | ❌ 需优化 |
| Using join buffer | JOIN 时没用到索引,用了 join buffer | ❌ 需加索引 |
| Select tables optimized away | 优化器直接从索引拿到聚合结果,不用访问表 | ✅ 极优 |
| Using where; Using index | 覆盖索引 + Server 层过滤 | ✅ 不错 |
| NULL | 没额外操作 | ✅ 正常 |
三、type 和 Extra 的常见组合
✅ 理想组合
type: const/ref/range + Extra: Using index
→ 索引精准命中 + 覆盖索引,不用回表不用排序,完美。
⚠️ 常见但可接受
type: ref/range + Extra: Using where
→ 用了索引但没覆盖,需要回表取数据再过滤。数据量不大时没问题。
⚠️ 用了索引但需排序
type: ref/range + Extra: Using filesort
→ 你上一轮的场景。索引命中了但排序没走索引,需要额外排。
❌ 需要警惕
type: ALL + Extra: Using filesort
→ 全表扫描 + 排序,双重打击,高并发下必炸。
❌ 更糟
type: ALL + Extra: Using temporary; Using filesort
→ 全表扫描 + 临时表 + 排序,通常是 GROUP BY 无索引导致的。
四、快速判断口诀
| 看什么 | 怎么判断 |
|---|---|
type 是 ALL |
🚨 先看能不能加索引 |
type 是 index |
⚠️ 比 ALL 好一点但也是扫全索引,看 rows 大不大 |
type 是 range/ref 但 rows 很大 |
⚠️ 索引选择性差,考虑优化索引 |
Extra 有 Using filesort |
看排序数据量,大就优化 |
Extra 有 Using temporary |
🚨 通常要改 SQL 或加索引 |
Extra 有 Using index |
✅ 不用管,这是好消息 |
五、实战速查
你之前的场景套进来:
-- 场景 AEXPLAIN SELECT * FROM AA WHERE test IN (1,2,3) ORDER BY sort ASC, id DESC;
期望看到:type: range, key: idx_test + Extra: Using filesort(可接受)
-- 场景 B(优化后)EXPLAIN SELECT test, sort, id FROM AA WHERE test = 1 ORDER BY sort ASC, id DESC;
期望看到:type: ref, key: idx_test_sort_id + Extra: Using index(完美)
