MySQL 执行计划(Execution Plan)是 MySQL 优化器为一条 SQL 语句生成的具体执行方案,它描述了数据库将如何执行这条语句,包括:
- 如何读取表数据(全表扫描还是使用索引)
- 表之间的连接顺序和连接方式(如嵌套循环、哈希连接)
- 数据过滤和排序的方式等
简单来说,执行计划就像 SQL 语句的 “执行路线图”,通过分析它可以了解语句的性能瓶颈,进而优化查询效率。
如何查看执行计划?
使用 EXPLAIN 或 EXPLAIN ANALYZE 命令,在 SQL 语句前添加即可:
-- 查看执行计划(不实际执行语句) EXPLAIN SELECT * FROM users WHERE age > 30; -- 查看执行计划并实际执行(MySQL 8.0+,返回更精确的耗时数据) EXPLAIN ANALYZE SELECT * FROM users WHERE age > 30;
执行计划核心字段解析
执行计划返回的结果包含多个字段,其中关键字段如下:
| 字段名 | 含义说明 |
|---|---|
id | 查询中每个操作的标识,值相同表示同一层级,值越大优先级越高 |
select_type | 查询类型(如 SIMPLE 简单查询、PRIMARY 主查询、SUBQUERY 子查询等) |
table | 当前操作涉及的表名 |
type | 访问类型(最重要的字段之一),表示数据的读取方式,性能从好到差大致为:system > const > eq_ref > ref > range > index > ALL( ALL 表示全表扫描,性能最差) |
possible_keys | 可能使用的索引列表(仅供参考,不一定实际使用) |
key | 实际使用的索引名称(NULL 表示未使用索引) |
key_len | 使用的索引长度(越长表示使用的索引字段越多,如复合索引可能只用到部分字段) |
rows | 预估需要扫描的行数(值越小越好) |
Extra | 额外信息(非常重要),如:Using index:使用覆盖索引(性能好)Using where:需要过滤数据Using filesort:需要额外排序(性能差)Using temporary:使用临时表(性能差) |
通过执行计划可以快速定位 SQL 性能问题,例如:
- 若
type为ALL且key为NULL,说明发生了全表扫描,可能需要添加索引 - 若
Extra出现Using filesort或Using temporary,说明需要优化排序或分组逻辑 - 若
rows远大于实际数据量,可能是统计信息过时,需要更新表统计信息(ANALYZE TABLE 表名)
示例
下面有一个实际例子,我们可以通过执行计划就可以分析出来这句sql执行慢的原因
首先我们创建一张表,有多个索引
CREATE TABLE `book` (
`id` bigint NOT NULL AUTO_INCREMENT COMMENT '主键ID',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '修改时间',
`creator` varchar(50) NOT NULL COMMENT '创建人',
`content` text NOT NULL COMMENT '消息内容',
`source` enum('api', 'user') NOT NULL COMMENT '来源(api或user)',
PRIMARY KEY (`id`),
KEY `idx_source_creator` (`source`, `creator`),
KEY `idx_creator_create_time` (`creator`, `create_time`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='消息表';
现在我们要执行一个查询语句
EXPLAIN
SELECT
source,
creator,
DATE(create_time) AS create_date,
COUNT(*) AS message_count
FROM
book
WHERE
source = 'api'
AND creator = 'specific_user'
GROUP BY
source,
creator,
DATE(create_time)
ORDER BY
create_date DESC;
我们想要分析这个语句的执行计划,可以这么写
-- 查看执行计划(不实际执行语句,快速分析索引和执行逻辑)
EXPLAIN
SELECT
source,
creator,
DATE(create_time) AS create_date,
COUNT(*) AS message_count
FROM
book
WHERE
source = 'api'
AND creator = 'specific_user'
GROUP BY
source,
creator,
DATE(create_time)
ORDER BY
create_date DESC;
结果如下:
![]()
这个执行计划中各个字段如下:
select_type:SIMPLE
table: book
partitions: NULL
type: ref
possible_keys:idx_source_creator,idx_creator_create_time
key:idx_source_creator
key_len:203
ref:const,const
rows:1
filtered:100.00
Extra: Using index condition; Using temporary; Using filesort
分析
我们可以看到在这个执行计划中最终选择的索引是idx_source_creator,我们知道在mysql索引选择的时候会选择可以忽略最多数据的,所以当我们多索引的时候就要固定查询条件,而且在mysql执行一条语句的时候仅仅只会走一个索引,因此当走了idx_source_creator索引后,即便我们给create_time建立了索引也不会走这个,所以在最后排序的时候Extra是要走多个的,特别是Using filesort这个是需要额外进行排序,那么在高并发的场景下,这样的排序方式会直接造成sql执行很慢堵塞系统,我们就可以按照执行计划来进行慢查询的排查
优化
选择id进行排序或者将create_time加入到sql选择的索引中才可以避免在高并发场景造成sql执行慢
138

被折叠的 条评论
为什么被折叠?



