极简工具箱

免费在线工具 · 本地计算 · 无需上传

EXPLAIN 怎么看:type、key、rows 与 Extra

`EXPLAIN` 输出十几列,真正决定性能的只有三四列。看懂 `type` 和 `Extra`,大部分慢查询的原因就明确了。

广告位(百度联盟)

一、先看 type:访问方式

从好到坏:

type含义评价
system表只有一行最好
const主键/唯一索引等值查极快
eq_ref联表时用主键/唯一索引很快
ref普通索引等值查好
range索引范围扫描可接受
index全索引扫描偏差(扫整个索引)
ALL全表扫描最差,重点优化

看到 ALL 且 rows 很大,基本就是问题所在。但也要看数据量:几百行的小表全表扫完全没问题。

二、possible_keys 与 key

两者不一致很常见:有可用索引但优化器算下来觉得全表更快(比如要扫 60% 的数据),这时 key 是 NULL、type 是 ALL。这种情况强行 FORCE INDEX 往往更慢,正确做法是改查询条件或调整索引。

三、rows 与 filtered

rows × filtered% 约等于最终参与的行数。如果 rows 是 100 万而 filtered 只有 1%,说明索引没起到过滤作用,只是扫了一遍。

四、Extra 里的关键信息

值含义处理
Using index覆盖索引,不回表好,保持
Using where存储引擎返回后再过滤常见,看过滤比例
Using filesort需要额外排序考虑给排序字段建索引
Using temporary用了临时表多见于 GROUP BY / DISTINCT,尽量优化
Using index condition索引条件下推好
Using join buffer联表没走索引给关联字段补索引

Using filesort 不一定真的写磁盘,但确实要额外排序,数据量大时很慢。消除办法是让 ORDER BY 的列顺序与索引一致:

-- 索引 (user_id, created_at)
SELECT * FROM orders WHERE user_id = 7 ORDER BY created_at DESC LIMIT 20;

这样能直接按索引顺序取,不用排序。

Using temporary 常见于 GROUP BY 非索引列、DISTINCT 多列、UNION。能通过调整索引或改写 SQL 消除就消除,消不掉也要控制数据量。

五、一个完整的判断流程

EXPLAIN SELECT id, amount FROM orders
WHERE user_id = 7 AND status = 1
ORDER BY created_at DESC
LIMIT 20;

假设输出:type=ref、key=idx_user、rows=12000、Extra=Using where; Using filesort。

判断:

  1. ref 说明用上了索引,但只用到 user_id。
  2. rows=12000 偏大,说明该用户的订单很多。
  3. Using filesort 说明排序没走索引。

优化:建联合索引 (user_id, status, created_at),让过滤和排序都在索引里完成,再配合覆盖索引把 amount 也带上,就能消除回表与排序。

六、EXPLAIN ANALYZE(MySQL 8.0.18+)

EXPLAIN ANALYZE SELECT ...;

它真正执行查询并给出实际耗时与行数,能和预估对比。预估 rows=100 实际 actual rows=100000 说明统计信息过期,可以 ANALYZE TABLE 更新。

注意它会真跑一遍,别在写操作或大表上随便用。

七、几个常见的误判

小结

type 看访问方式(ALL 最差),key 看实际用了哪个索引,rows × filtered 看扫描量,Extra 里的 filesort/temporary 是优化重点;8.0 用 EXPLAIN ANALYZE 对比预估与实际。

本文相关工具(本地计算,无需上传)

更多使用教程