从explain信息看mysql执行
MySQL的EXPLAIN命令用于分析SQL查询执行计划,展示优化器决策结果而不实际执行查询。其输出包含关键字段如type(访问类型)、key(实际使用索引)、rows(估算扫描行数)和Extra(额外信息),反映查询性能。通过分析这些字段,可以判断是否使用索引、是否存在全表扫描或临时表等性能问题。EXPLAIN还揭示了MySQL的查询执行原理,包括索引选择机制、连接顺序和覆盖索引等优化机会。高级
·
一、什么是 EXPLAIN?
EXPLAIN 是 MySQL 提供的一个用于分析 SQL 查询执行计划(Execution Plan)的命令。它不会真正执行 SQL,而是告诉你 MySQL 打算如何执行这条语句。
语法:
EXPLAIN SELECT ...;
-- 或更详细的格式(MySQL 5.6+)
EXPLAIN FORMAT=JSON SELECT ...;
二、EXPLAIN 输出字段详解(以传统表格格式为例)
| 列名 | 含义 | 关键原理说明 |
|---|---|---|
| id | 查询中 SELECT 的序列号 | id 相同表示同一层级;id 越大优先级越高(子查询);NULL 表示结果集合并(如 UNION) |
| select_type | SELECT 类型 | 如 SIMPLE(简单查询)、PRIMARY(最外层)、SUBQUERY(子查询)、DERIVED(派生表)、UNION 等,反映查询结构复杂度 |
| table | 涉及的表名 | 可能是实际表、别名、或 <derivedN>(派生表) |
| partitions | 匹配的分区(若使用分区表) | 显示查询涉及哪些分区,体现分区裁剪(Partition Pruning)能力 |
| type | 访问类型(最重要之一) | 表示 MySQL 如何查找行: • system/const:主键或唯一索引等值查询 • eq_ref:主键/唯一索引连接 • ref:非唯一索引等值 • range:范围扫描 • index:全索引扫描 • ALL:全表扫描(性能最差) |
| possible_keys | 可能用到的索引 | 优化器考虑使用的索引候选 |
| key | 实际使用的索引 | 若为 NULL,说明未走索引 |
| key_len | 使用索引的长度(字节) | 可判断复合索引用了前几列(如 INT=4字节,VARCHAR(255) utf8mb4 最多1020字节+2) |
| ref | 与索引比较的列或常量 | 如 const、func、或某表的字段 |
| rows | 估算扫描行数 | 越小越好,反映选择性 |
| filtered | 按表条件过滤后剩余百分比 | rows × filtered% ≈ 实际参与后续操作的行数 |
| Extra | 额外信息(极其重要) | 常见值: • Using index:覆盖索引(无需回表) • Using where:服务层过滤 • Using temporary:用临时表(如 GROUP BY 无索引) • Using filesort:无法用索引排序,需额外排序 • Using index condition:索引条件下推(ICP) |
三、从 EXPLAIN 看 MySQL 查询执行原理
1. 查询解析与优化
- MySQL 解析 SQL → 生成 AST(抽象语法树)
- 优化器基于统计信息(如索引基数、表大小)选择最优执行路径
EXPLAIN展示的就是优化器决策结果
2. 索引选择机制
- 优化器评估
possible_keys中每个索引的成本(I/O + CPU) - 成本最低者被选为
key - 若
key为 NULL,可能因为:- 无合适索引
- 全表扫描比走索引更快(如返回大量数据)
3. 连接顺序(Join Order)
- 多表 JOIN 时,MySQL 决定驱动表(先查哪张表)
EXPLAIN中靠前的表通常是驱动表- 驱动表应尽量小(减少嵌套循环次数)
4. 执行方式
- Nested-Loop Join:MySQL 主要连接算法
- 若出现
Using temporary; Using filesort,说明需要中间结果处理,性能较差
5. 覆盖索引 vs 回表
Using index表示所需字段都在索引中,避免回表(InnoDB 聚簇索引特性)- 否则需通过主键回聚簇索引取数据(额外 I/O)
四、实战示例
EXPLAIN SELECT u.name, o.amount
FROM users u
JOIN orders o ON u.id = o.user_id
WHERE u.status = 'active';
假设:
users(id PK, status, name)orders(id PK, user_id, amount)users有索引(status)orders有索引(user_id)
理想 EXPLAIN 结果:
users表:type=ref, key=status, Extra=Using index conditionorders表:type=ref, key=user_id, Extra=Using where
说明:
- 先用
status索引快速定位活跃用户 - 再用
user_id索引关联订单 - 若
SELECT字段都在索引中,则可能Using index
五、高级技巧
-
使用
EXPLAIN ANALYZE(MySQL 8.0+)- 不仅显示计划,还显示实际执行时间、循环次数等
EXPLAIN ANALYZE SELECT ...; -
查看优化器 trace
SET optimizer_trace="enabled=on"; SELECT ...; SELECT * FROM information_schema.optimizer_trace;- 可看到为何没选某个索引、成本计算细节
六、总结
通过 EXPLAIN,我们可以洞察:
- MySQL 是否使用了索引
- 查询是否高效(避免全表扫描、临时表、文件排序)
- 连接顺序是否合理
- 是否存在回表、覆盖索引等优化机会
核心原则:
让 MySQL 尽可能少读数据、少排序、少临时表、快定位。
更多推荐


所有评论(0)