在 MySQL 的 EXPLAIN
执行计划中,type
字段表示查询的访问类型,即 MySQL 在查询时使用的数据检索方法。不同的 type
值表示不同的查询效率,通常 system
是最优的,而 ALL
是最差的。以下是这些 type
值的详细说明及其排序:
system > const > eq_ref > ref > range > index > ALL
1. system
(性能最优)
-
说明:
- 该表只有一行记录(如
system
表,或者只有一条记录的MyISAM
表)。 - 相当于
const
,但只适用于单行数据的情况。
- 该表只有一行记录(如
-
示例:
EXPLAIN SELECT * FROM singleton_table;
-
特点:
- 由于表只有一行,直接读取该行即可,不涉及索引扫描或全表扫描。
- 访问代价极低。
2. const
(常量查询)
-
说明:
- 适用于 唯一索引(PRIMARY KEY 或 UNIQUE) 查询,并且查询条件是常量。
- MySQL 仅需查询一次,就能获取数据。
- 适用于
WHERE
子句中的主键或唯一索引等查询。
-
示例:
EXPLAIN SELECT * FROM employees WHERE emp_id = 100;
-
特点:
- 查询结果最多返回一行。
- 查询优化器会在编译阶段就确定查询结果,速度极快。
- 适用于主键或唯一索引的等值查询。
3. eq_ref
(唯一索引等值匹配)
-
说明:
eq_ref
用于 主键(PRIMARY KEY)或唯一索引(UNIQUE KEY) 的等值查询,通常出现在多表JOIN
操作中。- 对于每一行来自主表的数据,子表最多只会返回一条匹配记录。
-
示例:
EXPLAIN SELECT e.emp_id, d.dept_name FROM employees e JOIN departments d ON e.dept_id = d.dept_id;
-
特点:
- 每次查询只返回一行数据(因为
eq_ref
必须基于PRIMARY KEY
或UNIQUE
索引)。 - 查询优化效果非常好。
- 常见于
JOIN
语句中,被连接表的主键或唯一索引用于匹配主表的字段。
- 每次查询只返回一行数据(因为
4. ref
(普通索引等值匹配)
-
说明:
ref
表示查询使用了非唯一索引(普通索引、非唯一的外键索引)。- 适用于非唯一索引或
JOIN
操作中的索引匹配,可能会返回 多行 数据。
-
示例:
EXPLAIN SELECT * FROM employees WHERE department_id = 5;
-
特点:
- 使用索引查找,但不是唯一匹配(可能匹配多行)。
- 常用于
JOIN
操作,或者在WHERE
子句中使用非唯一索引的查询。
5. range
(范围查询)
-
说明:
range
表示基于索引范围扫描,可以使用索引高效查找数据。- 常见的范围查询有
BETWEEN
、>
、<
、IN
等。
-
示例:
EXPLAIN SELECT * FROM employees WHERE salary BETWEEN 5000 AND 10000;
-
特点:
- 适用于索引列上的范围查询。
- 扫描索引的部分数据,比全表扫描(ALL)高效。
- 适用于
>
,<
,BETWEEN
,IN()
等操作符。
6. index
(全索引扫描)
-
说明:
index
表示 全索引扫描,相当于ALL
(全表扫描),但扫描的是索引而非数据行。- 适用于索引覆盖查询(即不需要回表查询)。
-
示例:
EXPLAIN SELECT idx_column FROM large_table;
-
特点:
- 比全表扫描(ALL)稍快,因为索引通常比整个表小。
- 不会使用
WHERE
过滤条件,会遍历整个索引。
7. ALL
(全表扫描,性能最差)
-
说明:
ALL
表示 全表扫描,意味着 MySQL 需要遍历整个表的所有数据行。- 适用于无索引的查询,或者查询无法利用索引。
-
示例:
EXPLAIN SELECT * FROM employees WHERE name = 'John Doe';
-
特点:
- 性能最差,因为需要扫描整张表。
- MySQL 可能会自动使用
Using filesort
或Using temporary
进行排序。 - 如果
ALL
出现在大表查询中,通常需要优化索引。
总结与排序
访问类型 | 适用情况 | 典型场景 | 速度 |
---|---|---|---|
system | 只有一行数据的表 | 读取单行数据 | 最快 |
const | 主键或唯一索引等值查询 | WHERE id = 1 | 极快 |
eq_ref | 主键或唯一索引 JOIN 查询 | JOIN ON primary_key | 非常快 |
ref | 非唯一索引等值查询 | WHERE department_id = 5 | 快 |
range | 范围查询 | WHERE age BETWEEN 18 AND 30 | 中等 |
index | 全索引扫描 | SELECT idx_column FROM table | 较慢 |
ALL | 无索引查询或全表扫描 | SELECT * FROM large_table | 最慢 |
优化建议
-
避免
ALL
(全表扫描):- 创建索引,提高查询效率。
- 使用
EXPLAIN
分析执行计划,确认索引是否被使用。
-
优化
range
(范围扫描):- 适当调整索引,避免 MySQL 过度扫描数据范围。
- 使用
BETWEEN
或IN()
查询时,确保索引列的数据分布合理。
-
提升
ref
和eq_ref
查询:- 使用外键关系,并确保
JOIN
语句涉及索引列。 - 采用
覆盖索引
,减少回表查询的次数。
- 使用外键关系,并确保
-
优化
index
(全索引扫描):- 避免
SELECT *
,只查询必要字段,减少数据量。 - 确保查询能利用索引,避免额外的
Using filesort
和Using temporary
。
- 避免
通过这些优化方法,可以减少数据库的负载,提高查询速度。