MySQL Explain详解

慢查询排查

         show status; -- 查询mysql数据库的一些运行状态
        show status like 'uptime';-- 查看mysql数据库启动多长时间,myisam存储引擎长时间启动需要进行碎片整理
        --查看慢查询
        show status like 'slow_queries';
        --查询慢查询时间
        show variables like 'long_query_time';
       -- 设置慢查询时间 
        set long_query_time = 0.5;    

 在日常工作中,我们会有时会开慢查询去记录一些执行时间比较久的SQL语句,找出这些SQL语句并不意味着完事了,些时我们常常用到explain这个命令来查看一个这些SQL语句的执行计划,查看该SQL语句有没有使用上了索引,有没有做全表扫描,这都可以通过explain命令来查看。所以我们深入了解MySQL的基于开销的优化器,还可以获得很多可能被优化器考虑到的访问策略的细节,以及当运行SQL语句时哪种策略预计会被优化器采用。(QEP:sql生成一个执行计划query Execution plan)

 使用:

 explain + SQL

 select * from user;

 explain select * from user;

mysql> explain select * from servers;
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
| id | select_type | table   | type | possible_keys | key  | key_len | ref  | rows | Extra |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+
|  1 | SIMPLE      | servers | ALL  | NULL          | NULL | NULL    | NULL |    1 | NULL  |
+----+-------------+---------+------+---------------+------+---------+------+------+-------+

expain出来的信息有10列,分别是id、select_type、table、type、possible_keys、key、key_len、ref、rows、Extra,下面对这些字段出现的可能进行解释:

一、id.  :select查询的序列号,包含一组数字,标识查询中执行select子句活操作表的顺序

    • 三种情况
      • ID相同,执行顺序从上到下;
      • ID不同,如果是子查询,ID的序号会递增,id的值越大优先级越高,越先被执行
      • ID相同不太,同时存在,先优先再顺序

二、select_type

表示SELECT语句的类型。它可以是以下几种取值:

  (1) SIMPLE(简单SELECT,不使用UNION或子查询等)

  (2) PRIMARY(查询中若包含任何复杂的子部分,最外层的select被标记为PRIMARY)

  (3) UNION(UNION中的第二个或后面的SELECT语句)

  (4) DEPENDENT UNION(UNION中的第二个或后面的SELECT语句,取决于外面的查询)

  (5) UNION RESULT(UNION的结果)

  (6) SUBQUERY(子查询中的第一个SELECT)

  (7) DEPENDENT SUBQUERY(子查询中的第一个SELECT,取决于外面的查询)

  (8) DERIVED(派生表的SELECT, FROM子句的子查询)

  (9) UNCACHEABLE SUBQUERY(一个子查询的结果不能被缓存,必须重新评估外链接的第一行)

三、table 表示查询的表。

显示这一行的数据是关于哪张表的,有时不是真实的表名字,看到的是derivedx(x是个数字,我的理解是第几步执行的结果)

mysql> explain select * from (select * from ( select * from t1 where id=2602) a) b;
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
| id | select_type | table      | type   | possible_keys     | key     | key_len | ref  | rows | Extra |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+
|  1 | PRIMARY     | <derived2> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  2 | DERIVED     | <derived3> | system | NULL              | NULL    | NULL    | NULL |    1 |       |
|  3 | DERIVED     | t1         | const  | PRIMARY,idx_t1_id | PRIMARY | 4       |      |    1 |       |
+----+-------------+------------+--------+-------------------+---------+---------+------+------+-------+

四、type

表示MySQL在表中找到所需行的方式,又称“访问类型”。

常用的类型有: ALL, index,  range, ref, eq_ref, const, system, NULL(从左到右,性能从差到好)

  ALL:Full Table Scan, MySQL将遍历全表以找到匹配的行

  index: Full Index Scan,index与ALL区别为index类型只遍历索引树

  range:只检索给定范围的行,使用一个索引来选择行

  ref: 表示上述表的连接匹配条件,即哪些列或常量被用于查找索引列上的值

  eq_ref: 类似ref,区别就在使用的索引是唯一索引,对于每个索引键值,表中只有一条记录匹配,简单来说,就是多表连接中使用primary key或者 unique key作为关联条件

  const、system: 当MySQL对查询某部分进行优化,并转换为一个常量时,使用这些类型访问。如将主键置于where列表中,MySQL就能将该查询转换为一个常量,system是const类型的特例,当查询的表只有一行的情况下,使用system

  NULL: MySQL在优化过程中分解语句,执行时甚至不用访问表或索引,例如从一个索引列里选取最小值可以通过单独索引查找完成。

------

  (1)	system
        该表仅有一行的系统表。这是const连接类型的一个特例。

    (2)	const
        数据表最多只有一个匹配行,它将在查询开始时被读取,并在余下的査询优化中作为常量对待。const表查询速度很快,因为它们只读取一次。const用于使用常数值比较PRIMARY KEY或UNIQUE索引的所有部分的场合。
        在下面查询中,tb1_name可用const表:
        SELECT  *  from tb1_name WHERE primary_key=1;
        SELECT * from tb1_name WHERE primary_key_part1=1 AND primary_key_part2=2

    (3) eq_ref
        对于每个来自前面的表的行组合,从该表中读取一行。当一个索引的所有部分都在查询中使用,并且索引是UNIQUE或者PRIMARY KEY时,即可使用这种类型。
        eq_ref可以用于使用“=”操作符比较带索引的列。比较值可以为常量或者一个在该表前面所读取的表的列的表达式。
        在下面例子中,MySQL可以使用eq_ref来处理ref_tables:
        SELECT * FROM ref_table,other_table WHERE ref_table.key_cloumn = other_table.cloumn;
        SELECT * FROM ref_table, other_tbale WHERE ref_table.key_cloumn_part1 = other_table.cloumn AND ref_table.key_cloumn_part2 = 1;

    (4)ref
        对于来自前面的表的任意组合,将从该表中读取所有匹配的行。这种类型用于索引既不是UNIQUE也不是PRIMARY KEY的情况,或者查询中使用了索引列在左子集,既索引中左边的部分列组合。ref可以用于使用=或者<=>操作符的带索引的列。
        以下的几个例子中,mysql将使用 ref 来处理ref_table:   
        select * from ref_table where key_column=expr; 
        select * from ref_table,other_table where ref_table.key_column=other_table.column; 
        select * from ref_table,other_table where ref_table.key_column_part1=other_table.column and ref_table.key_column_part2=1;

    (5)ref_or_null
        这种连接类型类似ref,不同的是mysql会在检索的时候额外的搜索包含null值的记录。在解决子查询中经常使用该链接类型的优化。
        在以下的例子中,mysql使用ref_or_null 类型来处理 ref_table:
        select * from ref_table where key_column=expr or key_column is null;

    (6)index_merge
        该链接类型表示使用了索引合并优化方法。在这种情况下,key列包含了使用的索引的清单,key_len包含了使用的索引的最长的关键元素。

    (7)unique_subquery
        该类型替换了下面形式的IN子查询的ref:
        value in (select primary_key from single_table where some_expr)

    (8)index_subquery
        这种连接类型类似 unique_subquery。可以替换IN子查询,不过它用于在子查询中没有唯一索引的情况下,
        例如以下形式:
        value in (select key_column from single_table where some_expr)

    (9)range
        只检索给定范围的行,使用一个索引来选择行。key列显示使用了哪个索引。ken_len包含所使用索引的最长关键元素。当使用 =, <>, >,>=, <, <=, is null, <=>, between, 或 in操作符,用常量比较关键字列时,类型为range。
        下面介绍几种检索制定行的情况:
        select * from tbl_name where key_column = 10; 
        select * from tbl_name where key_column between 10 and 20; 
        select * from tbl_name where key_column in (10,20,30); 
        select * from tbl_name where key_part1= 10 and key_part2 in (10,20,30);

    (10)index
         连接类型跟ALL一样,不同的是它只扫描索引树。它通常会比ALL快点,因为索引文件通常比数据文件小。

    (11)ALL
        对于前面的表的任意行组合,进行完整的表扫描。如果第一个表没有被标识为const的话就不大好了,在其他情况下通常是非常糟糕的。正常地,可以通过增加索引使得能从表中更快的取得记录以避免ALL。

五、possible_keys

指出MySQL能使用哪个索引在表中找到记录,查询涉及到的字段上若存在索引,则该索引将被列出,但不一定被查询使用

该列完全独立于EXPLAIN输出所示的表的次序。这意味着在possible_keys中的某些键实际上不能按生成的表次序使用。
如果该列是NULL,则没有相关的索引。在这种情况下,可以通过检查WHERE子句看是否它引用某些列或适合索引的列来提高你的查询性能。如果是这样,创造一个适当的索引并且再次用EXPLAIN检查查询

六、Key

key列显示MySQL实际决定使用的键(索引)

如果没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。

七、key_len

表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度(key_len显示的值为索引字段的最大可能长度,并非实际使用长度,即key_len是根据表定义计算而得,不是通过表内检索出的)当key 字段的值为NULL时,索引的长度就是NULL。注意,key_len的值可以告诉你在联合索引中MySQL会真正使用了哪些索引。

不损失精确性的情况下,长度越短越好 

八、ref

  表示使用哪个列或常数与索引一起来查询记录。

九、rows

    显示MySQL在表中进行查询时必须检查的行数。 

十、Extra

该列包含MySQL解决查询的详细信息,有以下几种情况:

Using where:列数据是从仅仅使用了索引中的信息而没有读取实际的行动的表返回的,这发生在对表的全部的请求列都是同一个索引的部分的时候,表示mysql服务器将在存储引擎检索行后再进行过滤

Using filesort:MySQL中无法利用索引完成的排序操作称为“文件排序”,如果出现,赶紧优化

Using temporary:表示MySQL需要使用临时表来存储结果集,常见于排序和分组查询

Using index: 表示直接访问索引就足够获取到所需要的数据,不需要通过索引回表;快

Using join buffer:改值强调了在获取连接条件时没有使用索引,并且需要连接缓冲区来存储中间结果。如果出现了这个值,那应该注意,根据查询的具体情况可能需要添加索引来改进能。

Impossible where:这个值强调了where语句会导致没有符合条件的行。

Select tables optimized away:这个值意味着仅通过使用索引,优化器可能仅从聚合函数结果中返回一行

总结:
• EXPLAIN不会告诉你关于触发器、存储过程的信息或用户自定义函数对查询的影响情况
• EXPLAIN不考虑各种Cache
• EXPLAIN不能显示MySQL在执行查询时所作的优化工作
• 部分统计信息是估算的,并非精确值
• EXPALIN只能解释SELECT操作,其他操作要重写为SELECT后查看执行计划。

原文地址:https://www.cnblogs.com/chenglc/p/10481994.html