官方参考文档:https://dev.mysql.com/doc/refman/8.0/en/explain-output.html
- 表的执行顺序
- 数据读取操作的操作类型
- 哪些索引被使用
- 哪些索引被实际使用
- 表之间的引用
- 每张表有多少行被优化器查询
查看Explain字段
| Column | JSON Name | Meaning | 描述 | | —- | —- | —- | —- | | id | select_id | The SELECT identifier | 选择标识符 | | select_type | None | The SELECT type | 表示查询的类型 | | table | table_name | The table for the output row | 输出行的表 | | partitions | partitions | The matching partitions | 匹配的分区 | | type | access_type | The join type | 表示表的连接类型 | | possible_keys | possible_keys | The possible indexes to choose | 表示查询时,可能使用的索引 | | key | key | The index actually chosen | 表示实际使用的索引 | | key_len | key_length | The length of the chosen key | 索引字段的长度 | | ref | ref | The columns compared to the index | 与索引比较的列 | | rows | rows | Estimate of rows to be examined | 扫描出的行数(估算的行数) | | filtered | filtered | Percentage of rows filtered by table condition | 按表条件过滤的行百分比 | | Extra | None | Additional information | 附件信息 |mysql> EXPLAIN SELECT 1;+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+| 1 | SIMPLE | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | NULL | No tables used |+----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+----------------+1 row in set, 1 warning (0.01 sec)
id列
id 列的编号是 select 的序列号,有几个 select 就有几个 id,并且 id 的顺序是按 select 出现的顺序增长的。
id 列越大执行优先级越高,id 相同则从上往下执行,id 为 NULL 最后执行。
select_type列
| select_type Value | JSON Name | Meaning | 描述 |
|---|---|---|---|
| SIMPLE | None | Simple SELECT (not using UNION or subqueries) |
简单Select查询,不使用 union 或者子查询 |
| PRIMARY | None | Outermost SELECT | 最外层查询 |
| UNION | None | Second or later SELECT statement in a UNION |
UNION中的第二个或后面的SELECT语句 |
| DEPENDENT UNION | dependent (true) | Second or later SELECT statement in a UNION , dependent on outer query |
UNION中的第二个或后面的SELECT语句,取决于外面的查询 |
| UNION RESULT | union_result | Result of a UNION | UNION的结果 |
| SUBQUERY | None | First SELECT in subquery |
子查询中的第一个SELECT,结果不依赖于外部查询 |
| DEPENDENT SUBQUERY | dependent (true) | First SELECT in subquery, dependent on outer query |
子查询中的第一个SELECT,依赖于外部查询 |
| DERIVED | None | Derived table | 派生表 |
| DEPENDENT DERIVED | dependent (true) | Derived table dependent on another table | 派生表依赖于另一个表 |
| MATERIALIZED | materialized_from_subquery | Materialized subquery | |
| UNCACHEABLE SUBQUERY | cacheable (false) | A subquery for which the result cannot be cached and must be re-evaluated for each row of the outer query | 无法缓存结果并且必须为外部查询的每一行重新评估的子查询 |
| UNCACHEABLE UNION | cacheable (false) | The second or later select in a UNION that belongs to an uncacheable subquery (see UNCACHEABLE SUBQUERY) |
table列
表示正在访问的哪张表
显示这一步所访问数据库中表名称(显示这一行的数据是关于哪张表的),有时不是真实的表名字,可能是简称,例如上面的e,d,也可能是第几步执行的结果的简称。
partitions列
type列
type 表示联接类型
| 联接类型 | 描述 |
|---|---|
| system | 该表只有一行(系统表),特殊的 const |
| const | 该表最多有一个匹配行,在查询开始时读取。因为只有一行,该行中该列的值可以被优化器的其余部分视为常量。 |
| eq_ref | 对于前面表中的每个行组合,从该表中读取一行。除了 systemand const类型之外,这是最好的连接类型。当连接使用索引的所有部分并且索引是一个 PRIMARY KEY或UNIQUE NOT NULL索引时使用它。 |
| ref | 对于先前表中的每个行组合,从该表中读取具有匹配索引值的所有行。ref如果联接仅使用键的最左前缀或键不是 aPRIMARY KEY或 UNIQUE索引(换句话说,如果联接无法根据键值选择单行),则使用。如果使用的键只匹配几行,这是一个很好的连接类型。 |
| fulltext | 连接是使用FULLTEXT 索引执行的。 |
| ref_or_null | 这种连接类型类似于 ref,但另外,MySQL 会额外搜索包含NULL值的行。这种连接类型优化最常用于解析子查询。 |
| index_merge | 此连接类型表示使用了索引合并优化。在这种情况下,key输出行中的列包含所使用索引的列表,并key_len包含所使用索引 的最长关键部分的列表。 |
| unique_subquery | unique_subquery 只是一个索引查找函数,完全替换子查询以提高效率。 |
| index_subquery | |
| range | |
| index | 该index联接类型是一样的 ALL,只是索引树被扫描 |
| ALL | 对先前表中的每个行组合进行全表扫描 |
possible_keys 列
指出 MySQL 能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用(该查询可以利用的索引,如果没有任何索引显示 null)
key 列
key 列显示 MySQL 实际决定使用的键(索引),必然包含在 possible_keys 中
key_len列
表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)
ref 列
列与索引的比较,表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值。
rows 列
估算出结果集行数,表示MySQL根据表统计信息及索引选用情况,估算的找到所需的记录所需要读取的行数
filtered 列
该 filtered 列指示按表条件过滤的表行的估计百分比。最大值为 100,这意味着没有发生行过滤。从 100 开始减小的值表示过滤量增加。 rows显示估计的检查行数,rows× filtered显示与下表连接的行数。例如,如果 rows是 1000 和 filtered50.00 (50%),则与下表连接的行数为 1000 × 50% = 500。
Filtered表示返回结果的行数占需读取行数的百分比 Filtered列的值越大越好 Filtered列的值依赖于统计信息
Extra 列
顾名思义,Extra列是用来说明一些额外信息的,我们可以通过这些额外信息来更准确的理解MySQL到底将如何执行给定的查询语句。
索引覆盖,就是select的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select列表中的字段,而不必根据索引再次读取数据文件,换句话说查询列要被所建的索引覆盖。
| Extra | 说明 |
|---|---|
| Using filesort | 说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行排序,MySQL无法利用索引完成的排序称为“文件排序” |
| Using temporary | 使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序 order by 和分组查询 group by |
| USING index | 表示相应的select操作中使用了覆盖索引(Covering index),避免访问了表的数据行,效率不错。如果同时出现 using where,标明索引被用来执行索引键值的查找。如果没有同事出现 using where,标明索引用来读取数据而非执行查找动作。 |
| using where | 标明使用了where过滤 |
| using join buffer | 使用了连接缓存 |
| impossible where | where子句的值总是false,不能用来获取任何元组。 |
| select tables optimized away | |
| distinct | 优化distinct操作,在找到第一匹配的元组后即停止找同样值得动作 |
添加索引建议
- 永远用小结果集驱动大的结果集;
- 索引最好设置在需要经常查询的字段中;
- 左连接索引添加在右表上,右连接索引添加在左表上;
- 全值匹配我最爱
- 最佳左前缀法则
- 不在索引列上做任何操作(计算、函数、类型转换),会导致索引失效而转向全表扫码
- 存储引擎不能使用索引中范围条件的右边的列(范围查询后,后面的索引失效;)
- 尽量使用覆盖索引(只访问索引的查询(索引列和查询列一致)),减少select *
- mysql 在使用不等于(!= 或者 <>)的时候无法使用索引会导致全表扫描
- is null,is not null 也无法使用索引
- like 以通配符开头 mysql 索引失效会变成全表扫描的操作
- 字符串不加单引号索引失效
- 少用or,用它来连接时索引失效
