大家好,我是小耶。上周讲了EXPLAIN的3个必看字段,评论区不少朋友说“够用但还想深入”。今天就把它彻底拆开,讲讲key_len怎么判断用了索引的哪几列,filtered如何评估回表代价,以及MySQL 8.0的EXPLAIN ANALYZE为什么比传统EXPLAIN更准。
1 问题背景:为什么只靠type还不够?
在日常优化中,type从ALL变成range或ref固然能大幅提升性能,但当多个索引可选时,优化器的选择是否正确?索引用了但扫描行数依然很大怎么办?这些仅靠传统EXPLAIN难以回答。
MySQL 8.0引入了EXPLAIN ANALYZE,可以输出实际执行的成本和时间;FORMAT=JSON则能展示优化器的代价估算。掌握这些,才能真正理解SQL慢在哪里。
2 核心概念:EXPLAIN输出列详解
以下列是按重要性排序的必看项:
- type:访问类型。从优到劣:
system>const>eq_ref>ref>range>index>ALL。ALL代表全表扫描,必须优化。 - possible_keys:可能用到的索引。若为
NULL,说明无可用的索引。 - key:实际使用的索引。若为
NULL,代表未走索引。 - key_len:实际使用的索引字节数。可推算索引中具体用了哪几列(例如
utf8mb4每字符4字节,key_len=4表示只用了第一列)。 - rows:预估需要扫描的行数。数字越大越慢。但此为估算值,与
filtered配合可估算回表行数。 - filtered:存储引擎层返回的数据经过WHERE条件过滤后剩余的比例。例如
rows=1000,filtered=10.00,表示最终大约返回100行。如果filtered很低且索引不包含所有WHERE列,说明需要回表过滤大量数据,可考虑覆盖索引。 Extra:附加信息。常见的有:
Using index:覆盖索引,不回表,好。Using index condition:索引下推,较好。Using where:需要回表过滤,通常正常。Using filesort:需要额外排序,应优化。Using temporary:使用临时表,应优化。
EXPLAIN ANALYZE(MySQL 8.0.18+):实际执行查询并输出每个步骤的实际耗时、循环次数、返回行数等,比估算准确。格式示例:
text-> Nested loop inner join (actual time=0.1..0.2 rows=10 loops=1)注意:它会真实执行,生产环境慎用。
3 案例解析:从执行计划定位一个真实慢查询
3.1 问题SQL
SELECT * FROM orders WHERE user_id = 123 ORDER BY order_date DESC;
原索引为 (user_id)。EXPLAIN结果:
| type | key | rows | Extra |
|---|---|---|---|
| ref | idx_user_id | 5000 | Using filesort |
rows=5000(该用户有5000条订单),Extra=Using filesort(因为order_date没有索引,需要额外排序)。经验证该查询耗时0.8秒。
3.2 优化过程
添加联合索引 (user_id, order_date)后:
| type | key | rows | Extra |
|---|---|---|---|
| ref | idx_user_date | 5000 | (空) |
无需filesort,耗时降至0.05秒。这里rows仍为5000,但Extra已无排序,且key_len可判断实际用了两列。
若需进一步优化,可改为覆盖索引 (user_id, order_date, status, amount) 避免回表,Extra会显示Using index。
3.3 使用FORMAT=JSON查看代价
EXPLAIN FORMAT=JSON SELECT ...;
输出中的cost_info块展示了read_cost、eval_cost、prefix_cost,可比较不同索引的代价估算,帮助理解优化器决策。
4 总结与建议
- 日常慢查询分析,先看
type和rows;若type不是ALL但rows很大,检查filtered和key_len;Extra中出现Using filesort或Using temporary几乎总是需要优化。 - MySQL 8.0用户可将
EXPLAIN ANALYZE用于测试环境,获取真实执行成本。 - 掌握这些,就不只是“能看懂”,而是能根据执行计划精准加索引或改写SQL。
理解执行计划是SQL调优的基石。从3个字段到全解读,你的优化能力会上一个台阶。
小耶在手,SQL 不愁。
还有什么想了解的,欢迎留言!小耶一定知无不言言无不尽……我们下次见~