一、EXPLAIN基础

1.1 什么是EXPLAIN

EXPLAIN SELECT * FROM users WHERE id = 10;

作用

  • 查看SQL执行计划
  • 不实际执行查询
  • 分析索引使用情况
  • 优化查询性能

1.2 基本用法

-- 方式1:EXPLAIN
EXPLAIN SELECT ...;

-- 方式2:DESCRIBE(同义词)
DESCRIBE SELECT ...;

-- 方式3:查看实际执行(MySQL 8.0.18+)
EXPLAIN ANALYZE SELECT ...;

二、id - 查询标识

2.1 含义

查询的执行顺序标识。

EXPLAIN SELECT * FROM users WHERE id = 10;

结果

id: 1  ← 简单查询

2.2 子查询

EXPLAIN SELECT * FROM users
WHERE id IN (SELECT user_id FROM orders);

结果

id  | table
----+--------
1   | users
2   | orders  ← 先执行id=2(子查询)

规则

  • id大的先执行
  • id相同,从上往下执行

三、select_type - 查询类型

3.1 SIMPLE

简单查询,无子查询或UNION。

EXPLAIN SELECT * FROM users WHERE id = 10;
-- select_type: SIMPLE

3.2 PRIMARY

最外层查询。

EXPLAIN SELECT * FROM users WHERE id IN (SELECT ...);
-- select_type: PRIMARY(外层查询)

3.3 SUBQUERY

子查询。

EXPLAIN SELECT * FROM users
WHERE id = (SELECT MAX(user_id) FROM orders);
-- 子查询:SUBQUERY

3.4 DERIVED

派生表(FROM子句中的子查询)。

EXPLAIN SELECT * FROM (SELECT * FROM users) AS t;
-- select_type: DERIVED

3.5 UNION

UNION查询。

EXPLAIN
SELECT * FROM users WHERE id = 1
UNION
SELECT * FROM users WHERE id = 2;
-- 第二个SELECT:UNION

四、table - 表名

显示查询的表名。

EXPLAIN SELECT * FROM users;
-- table: users

派生表

EXPLAIN SELECT * FROM (SELECT * FROM users) AS t;
-- table: <derived2>(派生表)

五、type - 访问类型(重要)

5.1 性能排序

system > const > eq_ref > ref > range > index > ALL
 最好                                          最差

5.2 system

表只有一行(系统表)。

EXPLAIN SELECT * FROM mysql.proxies_priv;
-- type: system

5.3 const

主键或唯一索引的等值查询。

EXPLAIN SELECT * FROM users WHERE id = 10;
-- type: const(最多一条记录)

5.4 eq_ref

JOIN时,主键或唯一索引的等值连接。

EXPLAIN SELECT * FROM orders o
JOIN users u ON o.user_id = u.id;
-- users表:eq_ref

5.5 ref

非唯一索引的等值查询。

EXPLAIN SELECT * FROM users WHERE name = '张三';
-- type: ref(普通索引)

5.6 range

范围查询。

EXPLAIN SELECT * FROM users WHERE id BETWEEN 10 AND 20;
-- type: range

5.7 index

全索引扫描。

EXPLAIN SELECT id FROM users;
-- type: index(扫描整个索引)

5.8 ALL

全表扫描(最差)。

EXPLAIN SELECT * FROM users WHERE age = 20;
-- type: ALL(无索引)

六、possible_keys - 可能使用的索引

EXPLAIN SELECT * FROM users WHERE name = '张三' AND age = 20;
-- possible_keys: idx_name, idx_age

含义:MySQL认为可能使用的索引。


七、key - 实际使用的索引

EXPLAIN SELECT * FROM users WHERE name = '张三' AND age = 20;
-- key: idx_name(实际选择的索引)

NULL:未使用索引。

EXPLAIN SELECT * FROM users WHERE age = 20;
-- key: NULL(全表扫描)

八、key_len - 索引长度

8.1 含义

使用的索引长度(字节数)。

-- 索引
CREATE INDEX idx_name ON users(name);  -- VARCHAR(50)

EXPLAIN SELECT * FROM users WHERE name = '张三';
-- key_len: 203(50*4+2+1,UTF8MB4)

8.2 计算规则

VARCHAR(N):
- UTF8:N * 3 + 2(长度) + 1(NULL标志)
- UTF8MB4:N * 4 + 2 + 1

INT:4字节
BIGINT:8字节
DATETIME:8字节

8.3 联合索引

CREATE INDEX idx_a_b ON table(a, b);  -- a INT, b INT

WHERE a = 1;
-- key_len: 4(只用了a)

WHERE a = 1 AND b = 2;
-- key_len: 8(用了a和b)

九、实战示例

示例1:优化前后对比

-- 优化前
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
-- type: ALL(全表扫描)
-- key: NULL

-- 创建索引
CREATE INDEX idx_user_id ON orders(user_id);

-- 优化后
EXPLAIN SELECT * FROM orders WHERE user_id = 123;
-- type: ref
-- key: idx_user_id

示例2:联合索引分析

CREATE INDEX idx_a_b_c ON table(a, b, c);

EXPLAIN SELECT * FROM table WHERE a = 1 AND b = 2;
-- key_len: 8(使用了a和b)

EXPLAIN SELECT * FROM table WHERE a = 1;
-- key_len: 4(只使用了a)

十、总结

核心字段

字段含义重点
id执行顺序大的先执行
select_type查询类型SIMPLE/PRIMARY/SUBQUERY
table表名-
type访问类型最重要!
possible_keys可能的索引-
key实际索引NULL=无索引
key_len索引长度判断索引使用情况

type优化目标

目标:至少达到range级别
- ✅ 理想:const/eq_ref/ref
- ⚠️ 可接受:range
- ❌ 需优化:index/ALL

记忆口诀

EXPLAIN分析很重要,type字段是关键,
const ref range最常见,index ALL要优化。
key显示用的索引,NULL表示没用上,
key_len索引长度看,判断联合索引用几列。

本文字数:约2,200字 难度等级:⭐⭐⭐⭐(性能分析)