MySQL 笔记:EXPLAIN 执行计划各列怎么看

· Mysql笔记 MySQL SQL优化 执行计划 · 0 阅读 · 约 6 分钟

前言

EXPLAIN 是排查慢 SQL 的第一现场。它只做解析不真正执行,所以在线上随手加也不会出事故。下面按列拆解,一条一条说清每列"能告诉你什么、不能告诉你什么"。

mysql> EXPLAIN SELECT id FROM blog_article WHERE category_id = 12
    -> ORDER BY published_at DESC LIMIT 10;
+----+-------------+--------------+------+--------------+---------+------+-----------------------------------------+
| id | select_type | table        | type | key          | key_len | ref  | rows | Extra                                   |
+----+-------------+--------------+------+--------------+---------+------+-----------------------------------------+
|  1 | SIMPLE      | blog_article | ref  | idx_category |       4 | const|    1 | Using index condition; Using filesort   |
+----+-------------+--------------+------+--------------+---------+------+-----------------------------------------+

5.7 完整列是:id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra。

type:访问方式,最关键的一列

从好到坏大致是这个顺序:

type 含义
system / const 主键或唯一索引等值,最多一行
eq_ref join 时按主键唯一索引匹配,每行外部表只回一行
ref 非唯一索引等值(或前缀)匹配,可能返回多行
range 索引范围扫描,BETWEEN、>、IN、右模糊
index 扫整棵索引树,比 ALL 省在不用读行数据
ALL 全表扫描,看到就要警惕

还有 index_merge、fulltext、ref_or_null、unique_subquery 等,属于特定场景。经验判断:等值查询出现 ALL 是缺索引,index 通常意味着覆盖索引全扫或者优化器宁可用索引顺序避免排序。

possible_keys 与 key

possible_keys 是候选,key 才是真正选中的。候选有、key 是 NULL,说明优化器算了一遍觉得不走更快——常见于表很小、或者命中比例太高等量级问题。反过来 key 有值不代表就快,还要接着看 rows 和 Extra。

key_len:索引实际用了几列

它是"用到索引的第几列"最直接的证据。计算规则:定长类型按字节数算(INT 是 4),变长类型是字符集字节乘长度再加 2 个长度字节,可空列再加 1。以 KEY (status, category, views) 为例,只用 status 时 key_len 是 1(TINYINT),用到 status 和 category 时是 1+4=5。最左前缀到底吃了几列,看这个数比猜 SQL 写法准。

rows 和 filtered 都是估算

rows 是优化器预计要检查的行数,来自索引统计信息(ANALYZE TABLE 会刷新),跟真实结果集往往有偏差,数据倾斜时更明显。filtered 是预计经过条件过滤后剩下的百分比,两者相乘是优化器估算 join 代价的输入。判断"要不要建索引"时把它们当量级参考,别当结论。

Extra:最信息密集的一列

  • Using index:覆盖索引,不用回表,最理想
  • Using index condition:索引条件下推 ICP,在引擎层先过滤
  • Using where: Server 层还要再过滤一遍
  • Using filesort:需要额外排序,看下一篇
  • Using temporary:需要临时表,多见于 GROUP BY 跟不上的场景
  • Using join buffer:join 没走索引,退化成块嵌套循环
  • Impossible WHERE、Select tables optimized away:分别是条件恒假、以及 MAX() 之类能被优化成直接读索引端点

两个补充用法

EXPLAIN FORMAT=JSON SELECT ...;      -- 看 cost_info,能看到预计成本
EXPLAIN FOR CONNECTION <connection_id>;  -- 5.7 支持,直接分析正在跑的线程

EXPLAIN 只显示计划,不显示实际执行时间。想确认优化器的行数估得准不准,改完索引再对比一次执行计划,比单看耗时可靠。

小结

  • type 定性质,key 定选择,key_len 定用了几列,rows 给量级,Extra 给细节
  • possible_keys 有而 key 为空,是优化器主动放弃,不一定是索引建错
  • 估算列会骗人,重要结论要用改索引前后的对比来支撑