登录后台

页面导航

本文编写于 2020 天前,最后修改于 1264 天前,其中某些信息可能已经过时。

在工作中,我们用于捕捉性能问题最常用的就是打开慢查询,定位执行效率差的 SQL,那么当我们定位到一个 SQL 以后还不算完事,我们还需要知道该 SQL 的执行计划,比如是全表扫描,还是索引扫描,这些都需要通过 EXPLAIN 去完成。EXPLAIN 命令是查看优化器如何决定执行查询的主要方法。可以帮助我们深入了解 MySQL 的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行 SQL 语句时哪种策略预计会被优化器采用。需要注意的是,生成的 QEP 并不确定,它可能会根据很多因素发生改变。MySQL 不会将一个 QEP 和某个给定查询绑定,QEP 将由 SQL 语句每次执行时的实际情况确定,即便使用存储过程也是如此。尽管在存储过程中 SQL 语句都是预先解析过的,但 QEP 仍然会在每次调用存储过程的时候才被确定。

EXPLAIN 显示了 MySQL如何使用索引来处理 select 语句以及连接表。可以帮助选择更好的索引和写出更优化的查询语句。

使用方法,在 select 语句前加上 explain 就可以了:

如:

explain select surname,first_name form a,b where a.id=b.id

EXPLAIN列的解释

table

显示这一行的数据是关于哪张表的

type

这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为 consteq_regrefrangeindexALL

type 显示的是访问类型,是较为重要的一个指标,结果值从好到坏依次是:system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

一般来说,得保证查询至少达到range级别,最好能达到ref。

possible_keys

显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句。

key

实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MYSQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname)来强制使用一个索引或者用IGNORE INDEX(indexname)来强制 MySQL 忽略索引。

key_len

使用的索引的长度。在不损失精确性的情况下,长度越短越好。

ref

显示索引的哪一列被使用了,如果可能的话,是一个常数。

rows

MySQL 认为必须检查的用来返回请求数据的行数。

Extra

关于MYSQL如何解析查询的额外信息。将在 表4.3 中讨论,但这里可以看到的坏的例子是 Using temporaryUsing filesort,意思 MySQL 根本不能使用索引,结果是检索会很慢

extra 列返回的描述的意义

Distinct:一旦MYSQL找到了与行相联合匹配的行,就不再搜索了。

Not exists: MySQL 优化了 LEFT JOIN,一旦它找到了匹配 LEFT JOIN 标准的行,就不再搜索了。

Range checked for each Record(index map:#):没有找到理想的索引,因此对于从前面表中来的每一个行组合,MySQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一。

Using filesort: 看到这个的时候,查询就需要优化了。MySQL需要进行额外的步骤来发现如何对返回的行排序。它根据连接类型以及存储排序键值和匹配条件的全部行的行指针来排序全部行。

Using index: 列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候。

Using temporary: 看到这个的时候,查询需要优化了。这里,MySQL 需要创建一个临时表来存储结果,这通常发生在对不同的列集进行 ORDER BY 上,而不是 GROUP BY 上。

Where used: 使用了 WHERE 从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型 ALLindex,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序)。

system: 表只有一行:system 表。这是 const 连接类型的特殊情况。

const: 表中的一个记录的最大值能够匹配这个查询(索引可以是主键或惟一索引)。因为只有一行,这个值实际就是常数,因为MySQL先读这个值然后把它当做常数来对待。

eq_ref: 在连接中,MySQL在查询时,从前面的表中,对每一个记录的联合都从表中读取一个记录,它在查询使用了索引为主键或唯一键的全部时使用。

ref: 这个连接类型只有在查询使用了不是惟一或主键的键或者是这些类型的部分(比如,利用最左边前缀)时发生。对于之前的表的每一个行联合,全部记录都将从表中读出。这个类型严重依赖于根据索引匹配的记录多少—越少越好。

range: 这个连接类型使用索引返回一个范围中的行,比如使用 >< 查找东西时发生的情况。

index: 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比 ALL 更好,因为索引一般小于表数据)。

ALL: 这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免

示例

mysql> explain select * from t_order;
+----+-------------+---------+------+---------------+------+---------+------+--------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows   | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------+
|  1 | SIMPLE      | t_order | ALL  | NULL          | NULL | NULL    | NULL | 100453 |       |
+----+-------------+---------+------+---------------+------+---------+------+--------+-------+
1 row in set (0.03 sec)

加上 extended 之后:

mysql> explain extended select * from t_order;
+----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows   | filtered | Extra |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+
|  1 | SIMPLE      | t_order | ALL  | NULL          | NULL | NULL    | NULL | 100453 |   100.00 |       |
+----+-------------+---------+------+---------------+------+---------+------+--------+----------+-------+
1 row in set, 1 warning (0.00 sec)

本文节选自:https://www.cnblogs.com/yycc/p/7338894.html