(8) SELECT
(9) DISTINCT
(11) <TOP_specification> <select_list>
(1) FROM <left_table>
(3) <join_type> JOIN <right_table>
(2) ON <join_condition>
(4) WHERE <where_condition>
(5) GROUP BY <group_by_list>
(6) WITH {CUBE ROLLUP}
(7) HAVING <having_condition>
(10) ORDER BY <order_by_list>
首先 sql 从里向外执行,而 id是一组数字,表示查询中执行select子句或操作表的顺序。
如果id相同,则执行顺序从上至下。
如果是子查询,id的序号会递增,id越大则优先级越高,越先会被执行。
id如果相同,则可以认为是一组,从上往下顺序执行,所有组中,id越高,优先级越高,越容易执行。
1)简单SELECT(不使用UNION或子查询等)
2) PRIMARY:最外层的select
3)DERIVED:派生表的SELECT(FROM子句的子查询)
4)UNION:UNION中的第二个或后面的SELECT语句
5)UNION RESULT:UNION的结果。
6)DEPENDENT UNION:UNION中的第二个或后面的SELECT语句,取决于外面的查询
7)SUBQUERY:子查询中的第一个SELECT
8)DEPENDENT SUBQUERY:子查询中的第一个SELECT,取决于外面的查询
PS:这里我总结了下子查询的in语句会用到DEPENDENT关键字,如果子查询是union则是DEPENDENT UNION;如果子查询是简单的条件语句则是DEPENDENT SUBQUERY。这里不一定准确是我自己总结的哈~~如果不对望指正
有时不是真实的表名字,看到的是derivedx(x是个数字,我的理解是第几步执行的结果)
MySQL执行计划EXPLAIN主要可以通过type来进行分析:
type表示MySQL在表中找到所需行的方式,又称“访问类型”,常见类型如下:(从上至下,效果依次变好)
ALL:Full Table Scan。 index:Full Index Scan。
range:索引范围扫描。
ref :非唯一性索引扫描。
eq_ref :唯一性索引扫描。
const,system:将查询转换为一个常量。
null:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引
ALL:ALL 表示”全表扫描”(full table scan), 性能是最差的几种查询之一,如果查询的表比较大,且查询频次高,对MySQL数据库有致命的性能影响。示例如下:
ename字段上没有索引,所以也是全表扫描。
index: index 表示“全索引扫描”(full index scan),其类型和ALL较类似,性能也是比较差; 和ALL区别在于只对索引树进行扫描,但索引没有起到过滤作用。
ID字段为主键索引,在索引中扫描。
range:索引范围扫描,对索引的扫描开始于某一点,返回匹配值域的行, 常见于between、<、>,IN等的查询
ref:针对于非唯一或主键索引,或使用二者”最左部分字段”索引的等值查询或多表join,查询效率由这个值返回的行数多少决定。
name和age和覆盖索引,这里只使用了name,即只使用了唯一性索引的一部分,故为ref。
eq_ref:eq_ref 使用于多表的join时,被驱动表的过滤字段是主键或唯一索引,查询效率很好。
MID对于表Manager是唯一的,主键索引,来与employee连接,故type为eq_ref。
const、system:const 针对主键或唯一索引的等值查询扫描,最多只返回一行数据。
system是const类型的特例,当查询的表只有一行的情况下, 使用system。
exployee中ID为主键索引,可以直接定位,故为const,而衍生后的结果集A中只有一条记录,故为type为system。
NULL:MySQL在优化过程中分解语句,执行时甚至不用访问表或索引。
ID= SELECT MIN(ID)说明ID已确定,使用EXPLAIN EXTENDED优化,所以type为null,mysql自动优化,无需去访问表或索引。
使用show warnings查看优化后得到的结果。
index_merge:MySQL查询优化器发现查询可以同时使用多个索引查询结果集进行并集或交集的情况,就会使用index_merge type。此时key字段有两个或多个索引, key_len/rows都分别有两个数值; 如果是并集操作”Using intersect”, 往往通过两个索引的字段,合并为一个索引,避免index_merge查询 下图中两个SQL一个是AND/OR, Using intersect 和Using union 分别表示使用两个索引后的交集和并集
表示MySQL查询优化器发现当前查询可能被使用地索引,但不一定能会利用,如果possible_key的列举的索引越多,往往说明索引创建不合理,查询效率不是最高效; 因为优化器会分析尽可能多的索引,评估哪个索引的“成本”消耗局部最低,这个评估过程消耗时间和资源的。
key数据列是MySQL实际选用的索引,如果它为空(或NULL),则MySQL不使用索引。
key_len的值可以告诉你在联合索引中mysql会真正使用了哪些索引。 在上例中,key_len是102,其中firstname占50字节,lastname占50字节,age占2字节(smallint存储大小为2字节)。如果MySQL只使用索引中的firstname部分,则key_len将是50。 在不损失精确性的情况下 ,key_len数据列里的值越小越好(意思是更快)。
ref数据列给出了关联关系中另一个数据表里的数据列的名字。
MySQL查询优化器根据统计信息,估算SQL要查找到结果集需要扫描读取的数据行数; 这个值非常直观显示SQL的效率好坏,原则rows越少越好。显然,这里最理想的数字就是1。
Using index和Using where会遇到的比较多,可以重点记下,其他的我没怎么遇到过了解即可,遇到具体问题可以查阅哈
1)Distinct
一旦MYSQL找到了与行相联合匹配的行,就不再搜索了
2)Not exists
MYSQL优化了LEFT JOIN,一旦它找到了匹配LEFT JOIN标准的行,就不再搜索了
3)Range checked for each
没有找到理想的索引,因此对于从前面表中来的每一个行组合,MYSQL检查使用哪个索引,并用它来从表中返回行。这是使用索引的最慢的连接之一
4)Using filesort
MySQL需额外的排序操作,不能通过索引顺序达到排序效果;又叫”文件排序“,易错误理论为排序结果过大,内存中不够需写磁盘文件排序。 一般有filesort,都建议优化去掉,CPU资源消耗大。 下图last_update排序,但此字段无索引,故需filesort
5)Using index
”覆盖索引扫描“,表示查询在索引树中就可查找所需数据,不用回表数据文件(回表操作),往往说明性能不错,这发生在对表的全部的请求列都是同一个索引的部分的时候
6)Using temporary
看到这个的时候,查询需要优化了。查询有使用临时表,一般出现于排序,分组和多表join的情况,查询效率不高,建议优化。
7)Using where
使用了WHERE从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题
先说到这,下面一篇给大家总结下如何选择索引列以及使用索引的注意事项。
EXPLAIN列的解释:
列 | 描述 |
---|---|
table | 显示这一行的数据是关于哪张表的。 |
type | 这是重要的列,显示连接使用了何种类型。从最好到最差的连接类型为 const、eq_reg、ref、range、index和ALL。 |
possible_keys | 显示可能应用在这张表中的索引。如果为空,没有可能的索引。可以为相关的域从WHERE语句中选择一个合适的语句。 |
key | 实际使用的索引。如果为NULL,则没有使用索引。很少的情况下,MySQL会选择优化不足的索引。这种情况下,可以在SELECT语句中使用USE INDEX(indexname) 来强制使用一个索引或者用IGNORE INDEX(indexname)来强制MySQL忽略索引。 |
key_len | 使用的索引的长度。在不损失精确性的情况下,长度越短越好。 |
ref | 显示索引的哪一列被使用了,如果可能的话,是一个常数。 |
rows | MySQL认为必须检查的用来返回请求数据的行数。 |
Extra | 关于MySQL如何解析查询的额外信息。将在表4.3中讨论,但这里可以看到的坏的例子是Using temporary和Using 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从句来限制哪些行将与下一张表匹配或者是返回给用户。如果不想返回表中的全部行,并且连接类型ALL或index,这就会发生,或者是查询有问题不同连接类型的解释(按照效率高低的顺序排序)。 |
system | 表只有一行 system 表。这是const连接类型的特殊情况 。 |
const | 表示通过主键或惟一索引一次就找到了,查找时间为 O(1),可以认为是个常数(constant),所以叫 const; |
eq_ref | 在 join 的时候,对于每个索引键,表中只有唯一一条记录与之匹配,简单来说就是多表连接中使用primary key或者 unique key作为关联条件; |
ref | 与 eq_ref 区别是用了非唯一索引扫描; |
range | 这个连接类型使用索引返回一个范围中的行,比如使用>或<查找东西时发生的情况。 |
index | 这个连接类型对前面的表中的每一个记录联合进行完全扫描(比ALL更好,因为索引一般小于表数据)。 |
ALL | 这个连接类型对于前面的每一个记录联合进行完全扫描,这一般比较糟糕,应该尽量避免。 |
REF:
[1] 细说MySQL Explain和Optimizer Trace简介
https://zhuoroger.github.io/2016/08/11/mysql-explain/
[2] 如何理解 MySQL 的执行计划
http://blog.decaywood.me/2017/04/07/the-execution-plan-of-MySQL/