2025-09-18
MySQL
00
请注意,本文编写于 167 天前,最后修改于 167 天前,其中某些信息可能已经过时。

目录

MySQL EXPLAIN 全面指南
📊 什么是EXPLAIN?
🔍 如何查看EXPLAIN
基本用法
详细格式(MySQL 8.0+)
📋 EXPLAIN输出列详解
🎯 关键字段详细解读
select_type(查询类型)
type(访问类型)性能关键
Extra(额外信息)
🚨 性能问题识别
需要立即优化的信号
示例:问题查询分析
🛠️ 优化建议
1. 添加合适索引
2. 重写查询
3. 避免全表扫描
📊 EXPLAIN实战案例
案例1:简单查询优化
案例2:关联查询优化
🎯 最佳实践
📝 总结

MySQL EXPLAIN 全面指南

📊 什么是EXPLAIN?

EXPLAIN是MySQL提供的查询分析工具,用于显示MySQL如何执行SQL语句,帮助开发者优化查询性能。

🔍 如何查看EXPLAIN

基本用法

sql
EXPLAIN SELECT * FROM table_name WHERE condition;

详细格式(MySQL 8.0+)

sql
EXPLAIN FORMAT=JSON SELECT * FROM table_name; -- 或 EXPLAIN ANALYZE SELECT * FROM table_name;

📋 EXPLAIN输出列详解

列名说明关键值解读
id查询标识符数字越大越先执行,相同id按顺序执行
select_type查询类型见下方详细说明
table访问的表名可能是表名、别名或
partitions匹配的分区显示使用的分区
type访问类型性能关键指标,见下方说明
possible_keys可能使用的索引查询可能使用的索引列表
key实际使用的索引实际选择的索引
key_len索引长度使用的索引字节数
ref索引比较的列显示与索引比较的列或常量
rows预估扫描行数估算需要检查的行数
filtered过滤百分比存储引擎层过滤后剩余行的百分比
Extra额外信息重要优化信息,见下方说明

🎯 关键字段详细解读

select_type(查询类型)

类型含义出现场景
SIMPLE简单查询不包含子查询或UNION
PRIMARY最外层查询包含子查询的主查询
SUBQUERY子查询WHERE子句中的子查询
DERIVED派生表FROM子句中的子查询
UNIONUNION查询UNION中的第二个及以后的SELECT
UNION RESULTUNION结果UNION的结果集

type(访问类型)性能关键

从最优到最差排序:

类型描述性能
system系统表,只有一行⭐⭐⭐⭐⭐
const通过主键或唯一索引查询⭐⭐⭐⭐⭐
eq_ref关联查询,使用唯一索引⭐⭐⭐⭐⭐
ref使用非唯一索引查询⭐⭐⭐⭐
range索引范围扫描⭐⭐⭐⭐
index索引全扫描⭐⭐⭐
ALL全表扫描⭐(需要优化)

Extra(额外信息)

信息含义优化建议
Using index使用覆盖索引✅ 良好
Using where使用WHERE过滤⚠️ 可能需要优化
Using temporary使用临时表🔴 需要优化
Using filesort使用文件排序🔴 需要优化
Using join buffer使用连接缓冲⚠️ 可能需要优化

🚨 性能问题识别

需要立即优化的信号

  1. type: ALL - 全表扫描
  2. Using temporary - 使用临时表
  3. Using filesort - 文件排序
  4. rows 值很大 - 扫描行数过多
  5. key: NULL - 没有使用索引

示例:问题查询分析

sql
EXPLAIN SELECT * FROM users WHERE age > 30 ORDER BY name;

可能的问题输出:

  • type: ALL (全表扫描)
  • key: NULL (未使用索引)
  • Extra: Using where; Using filesort (WHERE过滤和文件排序)

🛠️ 优化建议

1. 添加合适索引

sql
-- 添加单列索引 CREATE INDEX idx_age ON users(age); CREATE INDEX idx_name ON users(name); -- 添加复合索引 CREATE INDEX idx_age_name ON users(age, name);

2. 重写查询

sql
-- 优化前(可能产生Using filesort) SELECT * FROM users WHERE age > 30 ORDER BY name; -- 优化后(使用覆盖索引) SELECT id, name, age FROM users WHERE age > 30 ORDER BY name;

3. 避免全表扫描

确保WHERE条件中的列有索引:

sql
-- 不好的写法 SELECT * FROM users WHERE YEAR(create_time) = 2023; -- 好的写法 SELECT * FROM users WHERE create_time >= '2023-01-01' AND create_time < '2024-01-01';

📊 EXPLAIN实战案例

案例1:简单查询优化

sql
-- 优化前 EXPLAIN SELECT * FROM products WHERE price > 100; -- 添加索引后 CREATE INDEX idx_price ON products(price); EXPLAIN SELECT * FROM products WHERE price > 100;

案例2:关联查询优化

sql
EXPLAIN SELECT u.name, o.order_date FROM users u JOIN orders o ON u.id = o.user_id WHERE u.city = 'Beijing';

优化建议:

  • users.city上添加索引
  • orders.user_id上添加索引

🎯 最佳实践

  1. 定期分析慢查询
  2. 为频繁查询的列添加索引
  3. 避免在WHERE子句中使用函数
  4. 使用覆盖索引减少回表
  5. 监控Using temporaryUsing filesort

📝 总结

检查项良好迹象需要优化
typeconst, ref, rangeALL, index
key使用索引NULL
rows数值小数值大
ExtraUsing indexUsing temporary, Using filesort

通过EXPLAIN分析,可以系统性地识别和解决SQL性能问题,显著提升数据库查询效率。

本文作者:sea-whales

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!