MySQL执行计划解读
MySQL执行计划解读
- MySQL执行计划解读
- 什么是MySQL执行计划?
- 执行计划的核心作用
- 如何查看执行计划?
- 执行计划字段解读
MySQL执行计划解读
什么是MySQL执行计划?
MySQL 执行计划(Execution Plan)是 MySQL 优化器为一条 SQL 查询生成的详细执行方案,它描述了数据库将如何执行这条查询,包括:将访问哪些表、使用什么索引、如何连接多个表、扫描多少数据行等关键信息。
简单来说,执行计划就像查询的 “路线图”—— 优化器根据表结构、索引、数据量、SQL 语法等因素,计算出它认为 “最高效” 的执行方式,并以结构化表格的形式展示出来。
执行计划的核心作用
- 分析查询性能瓶颈:通过执行计划可以判断查询是否使用了索引、是否进行了全表扫描、是否需要排序或临时表等,这些都是影响性能的关键因素。
- 指导 SQL 优化:根据执行计划的反馈,开发者可以调整 SQL 语句(如优化 WHERE 条件)、添加合适的索引,或修改表结构来提升查询效率。
- 理解优化器逻辑:执行计划能反映 MySQL 优化器的决策过程,帮助开发者理解 “为什么查询会这么慢”。
如何查看执行计划?
在 SQL 语句前添加 EXPLAIN
关键字即可生成执行计划,以电商系统中的订单表orders
为例:
创建订单表
CREATE TABLE orders (-- 订单主键(自增ID,唯一标识订单)order_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '订单ID',-- 关联用户表的外键(表示该订单所属用户)user_id BIGINT UNSIGNED NOT NULL COMMENT '用户ID(关联users表)',-- 订单编号(业务唯一标识,如生成规则:年月日+随机数)order_no VARCHAR(50) NOT NULL COMMENT '订单编号',-- 订单总金额(单位:分,避免浮点精度问题)total_amount INT NOT NULL COMMENT '订单总金额(分)',-- 订单状态(枚举:待支付、已支付、已取消、已发货、已完成等)status TINYINT NOT NULL COMMENT '订单状态:0-待支付,1-已支付,2-已取消,3-已发货,4-已完成',-- 支付方式(枚举:微信、支付宝、银行卡等)pay_type TINYINT DEFAULT NULL COMMENT '支付方式:1-微信,2-支付宝,3-银行卡',-- 支付时间pay_time DATETIME DEFAULT NULL COMMENT '支付时间',-- 收货地址信息(冗余存储,避免依赖地址表变动)receiver VARCHAR(50) NOT NULL COMMENT '收货人',receiver_phone VARCHAR(20) NOT NULL COMMENT '收货人电话',receiver_address VARCHAR(255) NOT NULL COMMENT '收货地址',-- 订单创建时间和更新时间(用于排序和跟踪)created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',-- 主键约束PRIMARY KEY (order_id),-- 唯一索引(确保订单编号不重复)UNIQUE KEY uk_order_no (order_no),-- 普通索引(用于按用户查询订单、按状态筛选、按时间排序)KEY idx_user_id (user_id),KEY idx_status (status),KEY idx_created_at (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单表';
测试执行计划
EXPLAIN SELECT * FROM orders WHERE user_id = 100 AND created_at > '2023-01-01';
执行计划字段解读
执行后会返回一张表格,包含 12 个核心字段(如 type
、key
、rows
、Extra
等),每个字段都代表执行计划的一个关键维度。
-
id
查询的序列号,多表关联或子查询时会有多个 ID,代表执行顺序(ID 越大越先执行)。
-
select_type
查询类型,如
SIMPLE
(简单查询)、PRIMARY
(主查询)、SUBQUERY
(子查询)等。 -
table
当前行对应的表名(或别名)。
-
partitions
在 MySQL 执行计划中,
partitions
字段用于显示查询实际访问的分区表分区,仅当查询涉及分区表时才有意义(非分区表的该字段值为NULL
)。 -
type
访问类型,最关键的列之一,反映查询效率:
system
:表只有一行(最优)const
:通过主键 / 唯一索引查询,最多返回一行eq_ref
:多表关联时,对每个前表行,后表只有一行匹配ref
:非唯一索引匹配,可能返回多行range
:索引范围查询(如BETWEEN
、IN
)index
:扫描整个索引(比全表扫描好)ALL
:全表扫描(最差,需优化)
-
possible_keys
可能使用的索引(仅供参考,不一定实际使用)。
-
key
实际使用的索引(
NULL
表示未使用索引)。 -
key_len
索引使用的字节长度(越短越好,说明索引利用率高)。
-
ref
表示哪些列或常量被用来查找索引列上的值(如
const
表示常量)。当type
为ref
时,ref
列必然有值(表示匹配的具体内容),说明查询使用了非唯一索引,可能返回多条符合条件的记录。-
const
:当查询条件是索引列 = 常量时,ref
会显示const
,表示用固定值匹配索引:EXPLAIN SELECT * FROM orders WHERE user_id = 100;
-
列名:多表关联查询时,若用一张表的列去匹配另一张表的索引列,
ref
会显示关联的列名: -
函数或表达式:若查询条件包含函数或表达式,
ref
可能显示func
,表示用函数计算结果匹配索引
-
-
rows
优化器估计需要扫描的行数(值越小越好)。
-
Extra
额外信息,包含大量优化线索:
Using index
:覆盖索引(无需回表,最优)Using where
:使用WHERE
过滤,但未使用索引Using filesort
:需额外排序(消耗性能,尽量避免)Using temporary
:使用临时表(消耗性能,尽量避免)Using join buffer
:多表关联未使用索引,使用连接缓冲区