使用EXPLAIN加上SELECT语句可以获取优化器的查询执行计划

MySQL会在查询上设置一个标记,当执行查询时,这个标记会返回关于在执行计划中每一步的信息,而不是执行它。它会返回一行或多行信息,一个表示一张表,显示出执行计划中的每一部分和执行的次序

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

复杂的查询如from子句中包含查询,select列中也包含查询,则执行顺序为,先执行外层查询,再执行from子句中的子查询,最后执行select列表中的子查询

下面是查询结果的一个示例:

| id  | select_type | table    | type   | possible_keys | key           | key_len | ref     | rows  | Extra |

| 1  | SIMPLE       | scores | const | PRIMARY       | PRIMARY | 8           | const | 1       |           |

1 row in set

实际上EXPLAIN后的SELECT语句的from子句包含子查询时,MySQL会执行子查询,再将结果放在一个临时表中,然后完成外层查询优化。

 

其实EXPLAIN只是一个近似的结果,有时甚至会相差甚远,下面是EXPALIN的一些限制

  1、EXPLAIN不会告诉你触发器、存储过程或UDF会如何影响查询的

  2、它并不支持存储过程。尽管可以手动抽取查询并单独地对齐进行EXPLAIN操作

  3、它并不会告诉你MySQL在查询执行中所做的特定优化

  4、它并不会显示关于查询的执行计划的所有信息

  5、它并不区分具有相同名字的事物,例如对内存排序和临时文件排序都使用filesort,并且对于磁盘上和内存中的临时表都显示Using temporary

  6、可能会误导。例如,对一个有着很小LIMIT的查询显示全索引扫描,5.1及之后的版本中EXPLAIN关于检查的行数会显示更精确的信息

 

EXPLAIN中的列

id列

  每一列的编号,如果有子查询和JOIN时,会显示多行,id按其在原始SQL语句中的顺序编号

select_type列

  显示对应行的查询是简单还是复杂,复杂类型分为三大类:简单子查询、所谓的派生表(在from子句中的子查询)、UNION查询,下面是可能的值

  SIMPLE  意味着查询不包含子查询和UNION

  PRIMARY  查询中有复杂部分,最外层的查询标记为PRIMARY

  SUBQUERY  包含不在FROM子句中子查询(在SELECT列表中的子查询)

  DERIVED  表示FROM子句有SELECT子查询,MySQL会先执行子查询并将结果放在临时表中

  UNION  UNION关键字后及以后的SELECT标记为UNION,UNION前的查询标记为PRIMARY

  UNION RESULT  用来从包含UNION的匿名临时表检索结果的SELECT标记为UNION RESULT

 

table列

  这一列显示了对应行正在访问哪个表,从这一列从上往下可以观察到MySQL的关联优化器为查询选择的关联顺序。包含多个JOIN的SELECT,从下往上先执行JOIN中的表

  <derivedN>  FROM子句有子查询时,N表示子查询的id,N执行EXPLAIN输出中的后面一行(先前引用)

  <unionid1,id2>  UNION RESULT的table列,id表示参与UNION的行的列表

 

type列

  显示访问类型,即MySQL决定如何查找表中的行,下面是最重要的访问方法,依次从最差到最优

  ALL

    全表扫描,意味着MySQL必须扫描整张表,从头到尾去找到需要的行。但是在查询中使用了LIMIT或者在Extra列显示Using distinct/not exists时type列也会显示ALL

    index

    也是全表扫描,只是MySQL扫描表时按照索引次序扫描而不是逐行扫描。它最大的优点是避免了排序,最大的缺点是要按索引次序读取整个表(使用索引扫描排序)

  range

    范围扫描,即一个有限制的索引扫描,始于索引中的某一点,返回匹配区域内的行。比全表扫描好些,它意味着不必遍历全部索引中的节点。

  ref

    

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄