在 MySQL 中,EXPLAIN 是一个非常重要的性能分析工具,用来查看 SQL 语句的执行计划,判断其执行效率,是否使用索引,是否存在全表扫描等问题。
✅ EXPLAIN 用法概览
基本语法:
EXPLAIN SELECT * FROM your_table WHERE some_column = 'value';
或者使用更详细的格式(MySQL 5.7+ 推荐):
EXPLAIN FORMAT=JSON SELECT ...
🔍 EXPLAIN 输出字段说明(普通模式)
示例:
EXPLAIN SELECT * FROM employees WHERE department_id = 10;
输出示例:
id select_type table partitions type possible_keys key key_len ref rows filtered Extra
1 SIMPLE employees NULL ref dept_idx dept_idx 4 const 100 100.00 Using where
字段解释:
字段 含义
id 查询中每个 SELECT 子句的标识符。多表查询时会有多个。
select_type 查询类型:SIMPLE(简单查询)、PRIMARY、SUBQUERY、DERIVED(派生表)等
table 正在访问的表名
partitions 使用的分区(如果有)
type 连接类型,越靠近 const,性能越好(从好到差:system > const > eq_ref > ref > range > index > ALL)
possible_keys 查询可能用到的索引
key 实际使用的索引
key_len 索引使用的字节长度
ref 哪一列或常量与 key 一起使用
rows MySQL 估计要读取的行数
filtered 行的过滤比例(百分比)
Extra 额外信息,如 Using where、Using index、Using temporary、Using filesort 等
📌 示例对比
🔴 示例 1:未使用索引(全表扫描)
EXPLAIN SELECT * FROM employees WHERE last_name = 'Smith';
如果 last_name 没有索引,type 是 ALL,表示全表扫描:
type: ALL
possible_keys: NULL
key: NULL
rows: 100000
Extra: Using where
✅ 示例 2:使用索引(条件列有索引)
-- 给 last_name 创建索引
CREATE INDEX idx_lastname ON employees(last_name);
-- 再执行查询
EXPLAIN SELECT * FROM employees WHERE last_name = 'Smith';
输出:
type: ref
possible_keys: idx_lastname
key: idx_lastname
rows: 10
Extra: Using where
✅ 示例 3:使用覆盖索引(Extra 中出现 Using index)
EXPLAIN SELECT last_name FROM employees WHERE last_name = 'Smith';
如果你只查询被索引的列(即 last_name),并且使用的是 idx_lastname:
Extra: Using index
意味着不需要回表操作,效率更高。
📖 EXPLAIN FORMAT=JSON 示例
EXPLAIN FORMAT=JSON SELECT * FROM employees WHERE department_id = 10;
输出是一个结构化的 JSON 对象,包含详细执行计划,非常适合配合程序分析。例如:
{
"query_block": {
"select_id": 1,
"table": {
"table_name": "employees",
"access_type": "ref",
"key": "dept_idx",
"used_key_parts": ["department_id"],
"rows_examined_per_scan": 100,
"filtered": 100,
"attached_condition": "employees.department_id = 10"
}
}
}
🛠 使用建议
情况 建议
type = ALL 表示全表扫描,考虑加索引
Extra 包含 Using filesort 说明使用了排序算法,考虑优化 ORDER BY
Extra 包含 Using temporary 表示使用了临时表,可能导致性能问题
possible_keys 有值但 key 为 NULL 有可用索引但没被用,可能是查询写法问题或统计信息不准确
🧪 示例练习题(可尝试)
假设你有表结构如下:
CREATE TABLE orders (
id INT PRIMARY KEY AUTO_INCREMENT,
customer_id INT,
order_date DATE,
amount DECIMAL(10,2),
INDEX idx_customer (customer_id)
);
试着运行以下 EXPLAIN 语句,观察差异:
EXPLAIN SELECT * FROM orders WHERE customer_id = 123;
EXPLAIN SELECT * FROM orders WHERE amount > 100; -- 没有索引
EXPLAIN SELECT order_date FROM orders WHERE customer_id = 123; -- 覆盖索引