第一次用explain命令时,我盯着输出结果看了半天,满屏的type、key、rows字段让人眼花缭乱。这就像拿到一份体检报告却看不懂各项指标的含义——明明数据就在眼前,却不知道哪些是重点、哪些需要警惕。执行计划就是SQL语句的"体检报告",它揭示了MySQL如何执行查询的内部机制。
explain的输出包含12个关键字段,但实际工作中我们最需要关注的是type、key、rows、Extra这四个核心指标。type列告诉你查询使用了哪种访问方法(是全表扫描还是索引查找),key列显示实际使用的索引名称,rows是预估需要检查的行数,Extra则包含额外的优化信息。这些字段的组合能快速定位SQL的性能瓶颈。
举个例子,当看到type=ALL时,就像发现体检报告中的某项指标严重超标——这意味着全表扫描,对于百万级数据表来说绝对是灾难性的。而看到type=ref时,则像是各项指标都在正常范围,说明索引使用得当。
type字段是执行计划的"心脏指标",它按照性能从优到劣有以下几种常见值:
WHERE id = 1这类查询。实际项目中,我遇到一个典型案例:用户列表页突然变慢,explain显示type=ALL。检查发现是在未索引的status字段上过滤,添加索引后type变为ref,查询时间从2秒降到50毫秒。
possible_keys列出可能使用的索引,而key是实际使用的索引。当这两个字段不一致时,就需要特别注意:
sql复制EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND status = 'paid';
假设表上有(user_id)单列索引和(user_id, status)联合索引,possible_keys会显示这两个索引,但key可能只使用(user_id)索引。这是因为优化器认为使用单列索引后通过status过滤的行数足够少。
我曾踩过一个坑:表上有(a,b)联合索引,但查询条件是WHERE b=1 AND a=2,由于条件顺序与索引顺序不一致,导致索引失效。调整条件顺序为a=2 AND b=1后,索引立即生效。
rows表示预估检查的行数,filtered表示条件过滤后剩余行数的百分比。这两个值需要结合看:
在分析慢查询时,我发现一个有趣现象:有时explain显示的rows很乐观,但实际执行却很慢。这是因为rows只是估值,当数据分布不均匀时(如90%数据集中在最近一个月),估值会严重偏离实际。
Extra字段包含优化器的额外提示,重要值包括:
上周我优化了一个报表查询,Extra显示Using temporary和Using filesort。通过添加(create_time, department)联合索引,两个提示都消失了,查询时间从8秒降到0.5秒。
SELECT MIN(id) FROM table且有id索引时。在电商项目中,商品搜索页曾出现性能问题。explain显示Using where; Using filesort,分析发现是在多个非索引字段上排序和过滤。通过建立包含这些字段的联合索引,并调整查询顺序以匹配索引顺序,性能提升了20倍。
原始查询:
sql复制SELECT * FROM orders
WHERE create_time > '2023-01-01'
AND status = 'shipped'
ORDER BY amount DESC;
执行计划显示:
优化步骤:
优化后执行计划:
多表关联查询:
sql复制EXPLAIN SELECT u.name, o.order_no
FROM users u JOIN orders o ON u.id = o.user_id
WHERE u.age > 18 AND o.status = 'paid';
常见问题:
优化方案:
当查询条件包含多个索引列时,MySQL可能使用Index Merge优化:
sql复制EXPLAIN SELECT * FROM products
WHERE category_id = 5 OR price < 100;
执行计划可能显示:
但要注意:
以下几种情况可能导致explain结果不准确:
我曾遇到一个案例:explain预估rows=100,实际执行却扫描了10万行。原因是该表刚经历大批量删除,统计信息未更新。执行ANALYZE TABLE后,explain结果变得准确。
MySQL 5.6+支持JSON格式的详细执行计划:
sql复制EXPLAIN FORMAT=JSON SELECT * FROM large_table WHERE id > 1000;
JSON格式包含更多细节:
对于复杂查询,JSON格式能提供更全面的分析视角。特别是查看"optimizer"字段,可以了解优化器是如何重写查询的。