---
url: /mysql/explain.md
---
# MySQL EXPLAIN 使用指南

## 概述

`EXPLAIN` 语句用于分析 SQL 查询的执行计划，帮助开发者理解 MySQL 如何执行查询并进行性能优化。

**来源**: https://dev.mysql.com/doc/refman/8.0/en/explain.html

***

## 基本语法

### TRADITIONAL 格式（默认）

```sql
EXPLAIN SELECT Name FROM country WHERE Code LIKE 'A%';
```

### TREE 格式

```sql
EXPLAIN FORMAT=TREE SELECT Name FROM country WHERE Code LIKE 'A%';
```

### JSON 格式（最详细）

```sql
EXPLAIN FORMAT=JSON SELECT Name FROM country WHERE Code LIKE 'A%';
```

***

## EXPLAIN 输出列详解

| 列名 | 说明 |
|------|------|
| id | 查询的序号，表示执行顺序 |
| select_type | 查询类型（SIMPLE、PRIMARY、SUBQUERY 等） |
| table | 表名 |
| partitions | 使用的分区 |
| type | 连接类型/访问类型 |
| possible_keys | 可能使用的索引 |
| key | 实际使用的索引 |
| key_len | 使用的索引长度（字节） |
| ref | 与索引比较的列或常量 |
| rows | 估计需要检查的行数 |
| filtered | 行过滤百分比 |
| Extra | 额外信息 |

**来源**: https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

***

## 连接类型（按性能从优到劣排序）

| 类型 | 说明 | 性能 |
|------|------|------|
| **system** | 表只有一行记录（const 的特例） | ⭐⭐⭐⭐⭐ |
| **const** | 最多匹配一行，通常为主键或 UNIQUE 索引查询 | ⭐⭐⭐⭐⭐ |
| **eq_ref** | 每个组合读取一行，使用 PRIMARY KEY 或 UNIQUE NOT NULL 索引 | ⭐⭐⭐⭐ |
| **ref** | 非唯一索引查询，可能返回多行 | ⭐⭐⭐ |
| **range** | 索引范围扫描 | ⭐⭐⭐ |
| **index** | 全索引扫描 | ⭐⭐ |
| **ALL** | 全表扫描（最差） | ⭐ |

**来源**: https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
**来源**: https://dev.mysql.com/doc/refman/8.0/en/dynindex-jointype.html

### Const 示例

```sql
SELECT * FROM _tbl_name_ WHERE _primary_key_=1;
SELECT * FROM _tbl_name_
  WHERE _primary_key_part1_=1 AND _primary_key_part2_=2;
```

### Eq_ref 示例

```sql
SELECT * FROM _ref_table_,_other_table_
  WHERE _ref_table_._key_column_=_other_table_._column_;
```

***

## Extra 列常见值

| 值 | 说明 |
|----|------|
| **Using index** | 覆盖索引，无需回表查询 |
| **Using where** | 使用了 WHERE 条件过滤 |
| **Using where with pushed condition** | 条件推送优化 |
| **Using temporary** | 使用了临时表（需优化） |
| **Using filesort** | 使用了文件排序（需优化） |
| **Backward index scan** | 反向索引扫描 |

**来源**: https://dev.mysql.com/doc/refman/8.0/en/engine-condition-pushdown-optimization.html
**来源**: https://dev.mysql.com/doc/refman/8.0/en/descending-indexes.html

***

## 实例解析

### 示例 1：范围查询

```sql
EXPLAIN SELECT a, b FROM t1 WHERE a < 2\G
```

输出：

```
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: t1
       type: range
possible_keys: a
        key: a
    key_len: 5
        ref: NULL
       rows: 2
     Extra: Using where with pushed condition
```

**来源**: https://dev.mysql.com/doc/refman/8.0/en/engine-condition-pushdown-optimization.html

### 示例 2：ORDER BY 使用索引

```sql
EXPLAIN SELECT * FROM t1 ORDER BY a ASC\G
```

输出：

```
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: t1
   partitions: NULL
       type: index
possible_keys: NULL
        key: a_desc_b_asc
    key_len: 10
       rows: 1
   filtered: 100.00
     Extra: Backward index scan; Using index
```

**来源**: https://dev.mysql.com/doc/refman/8.0/en/descending-indexes.html

### 示例 3：复合索引查询

```sql
EXPLAIN SELECT COUNT(*) FROM t1 WHERE i1 = 3 AND d = '2000-01-01'\G
```

输出：

```
*************************** 1. row ***************************
         id: 1
select_type: SIMPLE
      table: t1
       type: ref
possible_keys: PRIMARY,k_d
        key: k_d
    key_len: 8
        ref: const,const
       rows: 1
     Extra: Using index
```

**来源**: https://dev.mysql.com/doc/refman/8.0/en/index-extensions.html

***

## 最佳实践

1. **避免 `type=ALL`**：全表扫描通常是性能瓶颈
2. **关注 `rows` 列**：与 `EXPLAIN ANALYZE` 的实际结果对比
3. **优化 `Extra` 列**：尽量避免 `Using temporary` 和 `Using filesort`
4. **使用合适的索引**：确保 `key` 列显示预期的索引

**来源**: https://dev.mysql.com/doc/refman/8.0/en/explain-output.html

***

*文档生成时间：2026-05-19*
*数据来源：MySQL 8.0 Reference Manual*
