MySQL EXPLAIN 详解

MySQL 的 EXPLAIN 是分析和优化 SQL 性能的核心工具,它能揭示 SQL 的执行计划(查询优化器选择的执行路径)。以下是各字段的深度解析与实战示例:


一、EXPLAIN 关键字段详解

字段含义常见值及说明
id查询的序列号(多表关联时标识执行顺序)相同 id 按从上到下执行;不同 id 从大到小执行(id 越大优先级越高)
select_type查询类型SIMPLE:简单查询
PRIMARY:外层查询
SUBQUERY:子查询
DERIVED:派生表(FROM 子句中的子查询)
UNION:UNION 中的第二个及后续查询
table访问的表名可能是表名、别名、<derivedN>(派生表)、<unionM,N>(UNION 结果)
partitions匹配的分区分区表生效时显示命中的分区
type访问类型(性能核心指标)从优到差排序
system > const > eq_ref > ref > range > index > ALL
(至少达到 range,避免 ALL
possible_keys可能使用的索引查询涉及字段上存在的索引(不一定实际使用)
key实际使用的索引NULL 表示未用索引;优先选择覆盖索引
key_len索引使用的字节数数值越大说明索引利用率越高(联合索引中可判断使用了几个字段)
ref索引的引用关系const:常量值
func:函数结果
字段名:关联查询的字段
rows预估扫描的行数数值越小越好(实际可能偏差较大)
filtered存储引擎层过滤后剩余数据的百分比100 表示未过滤,值越小说明过滤效果越好
Extra额外执行信息(关键性能提示)Using index:覆盖索引
Using where:Server 层过滤
Using temporary:使用临时表
Using filesort:额外排序
Using index condition:索引下推

二、核心字段深度解析

1. type 访问类型详解
类型触发场景示例
system表只有一行数据(系统表)EXPLAIN SELECT * FROM mysql.proxies_priv;
const通过主键/唯一索引定位单条记录EXPLAIN SELECT * FROM users WHERE id = 1;
eq_ref多表 JOIN 时,使用主键/唯一索引关联(每行只匹配一条记录)EXPLAIN SELECT * FROM orders JOIN users ON orders.user_id = users.id;
ref使用非唯一索引扫描EXPLAIN SELECT * FROM users WHERE age = 30;(age 有索引)
range索引范围扫描(BETWEEN>INEXPLAIN SELECT * FROM orders WHERE amount > 1000;
index全索引扫描(比 ALL 快,但仍需遍历索引树)EXPLAIN SELECT COUNT(*) FROM products;(用二级索引统计)
ALL全表扫描(必须优化EXPLAIN SELECT * FROM logs WHERE content LIKE '%error%';
2. Extra 关键值解析
含义优化建议
Using index覆盖索引(查询列都在索引中,无需回表)优先使用覆盖索引
Using whereServer 层对存储引擎返回的数据进行过滤检查索引是否失效或缺失
Using temporary使用临时表(常见于 GROUP BYDISTINCTUNION优化 SQL 结构或增加索引
Using filesort额外排序(无法利用索引排序)ORDER BY 字段增加索引
Using index condition索引下推(ICP):在存储引擎层过滤数据MySQL 5.6+ 默认开启,无需干预
Select tables optimized away优化器已优化(如 MIN()/MAX() 直接走索引)表明优化成功

三、EXPLAIN 实战分析示例

场景:订单查询优化
EXPLAIN 
SELECT o.order_id, u.username, o.amount 
FROM orders o
JOIN users u ON o.user_id = u.id
WHERE o.status = 'paid'
ORDER BY o.create_time DESC
LIMIT 10;
执行计划结果:
idselect_typetabletypekeyrowsExtra
1SIMPLEorefidx_status1000Using filesort
1SIMPLEueq_refPRIMARY1NULL
问题诊断:
  1. o 表访问类型为 refstatus 字段有索引,但需扫描 1000 行。
  2. Extra: Using filesort:无法利用索引排序,需额外排序。
  3. 未利用覆盖索引:查询了 order_id, amount, create_time 但索引仅含 status
优化方案:
-- 创建联合索引(覆盖查询+排序)
ALTER TABLE orders ADD INDEX idx_status_time (status, create_time);

-- 重写后的执行计划:
idselect_typetabletypekeyrowsExtra
1SIMPLEorefidx_status_time100Using index
1SIMPLEueq_refPRIMARY1NULL

优化效果

  • 扫描行数从 1000 → 100
  • 消除 Using filesort
  • 实现覆盖索引 (Using index)

四、高级技巧

1. EXPLAIN FORMAT=JSON(MySQL 5.6+)
EXPLAIN FORMAT=JSON 
SELECT * FROM products WHERE category_id = 5;

输出包含详细成本计算、索引选择原因(cost_info),适合深度分析。

2. 可视化工具推荐
  • MySQL Workbench:图形化解释执行计划
  • Percona Toolkitpt-visual-explain
    pt-visual-explain explain_output.txt
    
3. 索引下推(ICP)示例
-- 表结构
CREATE TABLE sales (
  id INT PRIMARY KEY,
  region VARCHAR(20),
  amount INT,
  INDEX idx_region_amount (region, amount)
);

-- 查询
EXPLAIN SELECT * FROM sales 
WHERE region = 'Asia' AND amount > 1000;

结果
Extra: Using index condition
说明:存储引擎直接过滤 region='Asia' AND amount>1000,减少回表。


五、总结:EXPLAIN 优化四步法

  1. type:确保至少达到 range(避免 ALL/index
  2. key:检查是否使用正确索引(尤其联合索引)
  3. rows:预估扫描行数越少越好
  4. Extra:解决 Using temporaryUsing filesort 等警告

通过 EXPLAIN 理解优化器的选择逻辑,是定位慢 SQL 和设计高效索引的基石。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值