MySQL EXPLAIN 完全解读
- 一、一个EXPLAIN简单执行
- 二、简单了解
- 2.1. id:查询的标识符。
- 2.2. select_type:查询的类型。
- 2.3. table:输出结果集的表。
- 2.4. type:连接类型,这是MySQL决定如何查找表中行的方法。
- 2.5. possible_keys:可能用到的索引。
- 2.6. key:实际使用的索引。
- 2.7. key_len:使用的索引的长度。
- 2.8. ref:显示索引的哪一部分被使用了
- 2.9. rows:MySQL认为必须检查的用来获取查询结果的行数。
- 2.10. Extra:包含MySQL解决查询的详细信息。
- 三、重点讲解
- 3.1、SELECT_TYPE列表示MySQL如何查找表中的行。
- 3.2、type列表示MySQL如何查找表中的行。
- 3.2.1、一些常见的值及其含义
- 3.2.2、一些例子
- 3.3、EXPLAIN命令的key列用于显示MySQL在查询中使用的键(索引)
- 3.3.1、NULL:MySQL 没有使用任何键(索引)进行查询。
- 3.3.2、索引名称:如果 MySQL 使用了某个索引进行查询,那么 key 的值就是那个索引的名称。
- 3.3.3、PRIMARY:如果 MySQL 使用了主键索引进行查询,那么 key 的值就是 PRIMARY。
- 3.4、key_len列在MySQL的EXPLAIN输出中表示的是MySQL在索引中使用的字节数
- 3.5、ref 列显示了MySQL如何使用索引来查找数据
- 3.6、Extra列提供了关于查询执行方式的额外信息
一、一个EXPLAIN简单执行
二、简单了解
在MySQL中,EXPLAIN语句用于获取关于如何执行SQL语句的信息。以下是EXPLAIN输出的各个列的含义:
2.1. id:查询的标识符。
如果一个查询包含子查询,那么每个子查询都会有一个不同的id。
2.2. select_type:查询的类型。
这个列的值可以是SIMPLE(简单查询,不包含子查询或者UNION)、PRIMARY(查询中最外层的查询)、SUBQUERY(子查询中的第一个SELECT)、DERIVED(派生表的查询,MySQL会先执行这个查询,然后把结果放在临时表中)等。
2.3. table:输出结果集的表。
2.4. type:连接类型,这是MySQL决定如何查找表中行的方法。
常见的值有const、eq_ref、ref、range、index和ALL。
2.5. possible_keys:可能用到的索引。
2.6. key:实际使用的索引。
2.7. key_len:使用的索引的长度。
在不损失精度的情况下,长度越短越好。
2.8. ref:显示索引的哪一部分被使用了
如果可能的话,会显示哪个列或常数被用于查找索引列。
2.9. rows:MySQL认为必须检查的用来获取查询结果的行数。
2.10. Extra:包含MySQL解决查询的详细信息。
常见的值有Using index(表示MySQL只用到了索引,没有去读取实际的行,Using where(表示MySQL使用了WHERE过滤器)等。
三、重点讲解
3.1、SELECT_TYPE列表示MySQL如何查找表中的行。
SELECT_TYPE 是 MySQL 中 EXPLAIN 命令的输出列之一,用于描述查询中每个 SELECT 子句的类型。以下是一些可能的 SELECT_TYPE 值及其含义:
- SIMPLE:简单 SELECT(不使用 UNION 或子查询等)。
SELECT * FROM table1;
- PRIMARY:查询中如果包含任何复杂的子部分,最外层的 SELECT 被标记为 PRIMARY。
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
- SUBQUERY:在 SELECT 或 WHERE 列表中的第一个 SELECT 子查询。
SELECT * FROM table1 WHERE id IN (SELECT id FROM table2);
- DERIVED:在 FROM 列表中的子查询。
SELECT * FROM (SELECT id FROM table2) AS derived_table;
- UNION:如果第二个或后续的 SELECT 是 UNION 的一部分,则 SELECT_TYPE 是 UNION。
SELECT column1 FROM table1 UNION SELECT column2 FROM table2;
- UNION RESULT:从 UNION 表中选择结果的 SELECT。
(SELECT column1 FROM table1 UNION SELECT column2 FROM table2) ORDER BY 1;
3.2、type列表示MySQL如何查找表中的行。
3.2.1、一些常见的值及其含义
- const:这是最好的一种连接类型,表示MySQL能够在索引中一次就找到相关的行。这通常发生在你执行主键或唯一索引的查询,并且只返回一行结果的情况下。
- eq_ref:这是第二好的连接类型,表示MySQL在连接表时,对于每一行都只需要读取一次,这通常发生在你使用主键或唯一索引的情况下。
- ref:这种连接类型表示MySQL需要对每个外键组合执行一次查找,这通常发生在你使用非唯一索引或者非主键的情况下。
- range:这种连接类型表示MySQL在索引中进行范围查找,这通常发生在你使用BETWEEN、<、>、IS NULL或者IN等操作符的情况下。
- index:这种连接类型表示MySQL进行全索引扫描,这通常发生在你的查询只需要从索引中获取数据,而不需要查看实际的行数据的情况下。
- ALL:这是最差的连接类型,表示MySQL需要进行全表扫描,这通常发生在你的查询没有使用到索引的情况下。
3.2.2、一些例子
假设我们有一个名为users的表,其中包含id(主键)、name和email(唯一索引)三个字段。
- 如果我们执行查询
SELECT * FROM users WHERE id = 1
,那么type列的值就是const,因为MySQL可以通过主键一次就找到相关的行。 - 如果我们执行查询
SELECT * FROM users WHERE email = 'example@example.com'
,那么type列的值就是ref,因为MySQL需要对每个外键组合执行一次查找。 - 如果我们执行查询
SELECT * FROM users WHERE id BETWEEN 1 AND 1000
,那么type列的值就是range,因为MySQL在索引中进行范围查找。 - 如果我们执行查询
SELECT id FROM users ORDER BY id
,那么type列的值就是index,因为MySQL进行全索引扫描。 - 如果我们执行查询
SELECT * FROM users
,那么type列的值就是ALL,因为MySQL需要进行全表扫描。
3.3、EXPLAIN命令的key列用于显示MySQL在查询中使用的键(索引)
3.3.1、NULL:MySQL 没有使用任何键(索引)进行查询。
EXPLAIN SELECT * FROM table1 WHERE non_indexed_column = 'value';
在这个例子中,non_indexed_column 是一个没有索引的列,所以 key 的值为 NULL。
3.3.2、索引名称:如果 MySQL 使用了某个索引进行查询,那么 key 的值就是那个索引的名称。
EXPLAIN SELECT * FROM table1 WHERE indexed_column = 'value';
在这个例子中,indexed_column 是一个有索引的列,所以 key 的值就是该列的索引名称。
3.3.3、PRIMARY:如果 MySQL 使用了主键索引进行查询,那么 key 的值就是 PRIMARY。
EXPLAIN SELECT * FROM table1 WHERE id = 1;
3.4、key_len列在MySQL的EXPLAIN输出中表示的是MySQL在索引中使用的字节数
这个值是根据索引类型和索引字段的类型以及长度计算出来的。
例如,对于一个CHAR(10)类型的字段,如果它是一个字符串类型的索引,那么key_len的值就是10。如果这个字段是一个整数类型的索引,那么key_len的值就是4(因为整数类型的索引的长度是4字节)。 需要注意的是,key_len并不一定等于索引字段的实际长度。例如,对于一个VARCHAR(100)类型的字段,即使它的最大长度是100,但如果在查询中只使用了前10个字符,那么key_len的值就是10。 总的来说,key_len可以帮助你理解MySQL如何使用索引,以及索引的效率。在不损失精度的情况下,key_len的值越小,表示使用的索引越精简,查询效率可能会更高。
3.5、ref 列显示了MySQL如何使用索引来查找数据
例如,假设我们有一个名为 users 的表,其主键为 id,并且有一个名为 email 的唯一索引。以下是一些可能的情况:
- 使用主键进行查询:
EXPLAIN SELECT * FROM users WHERE id = 1;
在这个例子中,EXPLAIN 的输出可能会显示 ref 列的值为 const,表示我们使用了一个常量值(在这种情况下是 1)来查找主键索引。
2. 使用唯一索引进行查询:
EXPLAIN SELECT * FROM users WHERE email = 'user@example.com';
在这个例子中,EXPLAIN 的输出可能会显示 ref 列的值为 const,表示我们使用了一个常量值(在这种情况下是 ‘user@example.com’)来查找 email 索引。
3. 使用非唯一索引进行查询:
假设 users 表有一个非唯一索引 status,我们可以执行以下查询:
EXPLAIN SELECT * FROM users WHERE status = 'active';
在这个例子中,EXPLAIN 的输出可能会显示 ref 列的值为 const,表示我们使用了一个常量值(在这种情况下是 ‘active’)来查找 status 索引。
请注意,ref 列的值并不总是 const。如果我们使用了一个列的值来查找索引,那么 ref 列的值就会是那个列的名称。例如,如果我们有一个查询 SELECT * FROM users u JOIN orders o ON u.id = o.user_id,那么 EXPLAIN 的输出可能会显示 ref 列的值为 o.user_id,表示我们使用了 orders 表的 user_id 列的值来查找 users 表的主键索引。
3.6、Extra列提供了关于查询执行方式的额外信息
以下是一些可能出现在Extra列中的值及其含义:
1.Using index:这表示MySQL只需要读取索引,而不需要读取数据行。这通常发生在所有需要的数据列都包含在索引中的情况下。
2.Using where:这表示MySQL服务器将在存储引擎检索行后再进行过滤。这可能意味着存储引擎无法执行全部的过滤工作,可能是因为查询的某部分没有被索引覆盖。
3.Using temporary:这表示MySQL需要创建一个临时表来存储结果,这通常发生在对不同的列进行ORDER BY和GROUP BY的情况下。
4.Using filesort:这表示MySQL会对结果使用一个外部索引排序,而不是按照表中的索引顺序进行读取。这通常发生在ORDER BY或GROUP BY的列不是索引的一部分的情况下。
5.Range checked for each record (index map: N):这表示MySQL无法确定使用哪个索引,所以对于每一行数据,它都会检查是否可以使用索引。
6.Impossible WHERE noticed after reading const tables:这表示WHERE子句的条件总是false,当检查到这一点时,查询已经不再继续。