前言在MySQL中,我们知道添加索引可以提高查询效率,这基本是常识。但是有时候,我们还是会觉得加了索引之后SQL查询效率低下。我想看看是否使用了索引,扫描了多少行,加载表的顺序等等,如何查看?其实MySQL自带的SQL分析神器ExplainExecute执行计划就可以完成上面的事情!Explain有什么信息?首先确认实验的MySQL版本,这里使用的是5.7.31版本。只需要在SQL语句前加上explain关键字就可以查看执行计划。执行计划包括以下信息:id、select_type、table、partitions、type、possible_keys、key、key_len、ref、rows、filtered、Extra,共12个字段信息。然后创建三张表:CREATETABLE`tb_student`(`id`int(10)NOTNULLAUTO_INCREMENT,`name`varchar(36)NOTNULL,PRIMARYKEY(`id`),KEY`index_name`(`name`)USINGBTREE)ENGINE=InnoDBAUTO_INCREMENT=6DEFAULTCHARSET=utf8mb4COMMENT='学生表';创建表`tb_class`(`id`INT(10)primarykeynotnullauto_increment,`name`VARCHAR(36)NOTNULL,`stu_id`INT(10)NOTNULL,`tea_id`INT(10)NOTNULL)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='Classtable';CREATETABLE`tb_teacher`(`id`INT(10)primarykeynotnullauto_increment,`name`VARCHAR(36)NOTNULL)ENGINE=InnoDBDEFAULTCHARSET=utf8mb4COMMENT='教师表';解释详细执行计划explain的使用非常简单。只需要在SQL语句前加上关键字explain即可。关键是如何查看explain执行后返回的字段信息。这是关键点。1.idSELECT标识符。这是SELECT的查询序列号。SQL执行顺序的标识,SQL从大到小执行。id列有以下几点需要注意:当id相同时,执行顺序为从上到下。当id不同时,如果是子查询,id的序号会增加。id值越大,优先级越高,越早执行。EXPLAINSELECT*FROM`tb_student`WHEREidIN(SELECTstu_idFROMtb_classWHEREtea_idIN(SELECTidFROMtb_teacherWHERE`name`='马老师'));根据原理,当id不同时,SQL从大到小执行,如果id相同,则从上到下执行。2、select_type表示select查询的类型,用于区分各种复杂查询,如普通查询、联合查询、子查询等。SIMPLE表示最简单的查询操作,即查询SQL语句中没有子查询、并集等操作。PRIMARY当查询语句包含复杂查询的子部分时,代表复杂查询中最外层的select。SUBQUERY当select或where包含子查询时,子查询被标记为SUBQUERY。DERIVED是SQL语句中from子句中包含的子查询。UNION表示联合中的第二个和后续select语句。UNIONRESULT表示从union的临时表中读取数据。EXPLAINSELECTu.`name`FROM((SELECTs.id,s.`name`FROM`tb_student`s)UNION(SELECTt.id,t.`name`FROMtb_teachert))ASu;表示对id为2和3的select查询结果进行并集运算。MATERIALIZEDMATERIALIZED表示物化子查询,子查询来自视图。3.table表示输出结果集的表的表名。它不一定是真正的表,也可能是别名、临时表等。4.partitions表示SQL语句查询匹配到的分区信息。对于非分区表,该值为NULL。当查询是分区表时,会显示分区表命中的分区。5、type是需要关注的字段信息,表示查询时使用的是哪种类型。它是SQL优化中一个非常重要的指标。从最好到最差的顺序是:system>const>eq_ref>ref>range>index>ALL。system和const单表中最多只有一个匹配行,查询效率最高,所以这个匹配行中其他列的值在当前查询中可以被优化器当作常量处理。它通常出现在基于主键或唯一索引的查询中。system是const的特例。当表(系统表)中只有一个元组匹配时,就是系统。eq_ref主键或唯一键索引的所有部分都被连接使用,最多只会返回一条符合条件的记录,所以这种类型经常出现在多表连接查询中。与eq_ref相比,ref不使用唯一索引,而是使用普通索引或唯一索引的部分前缀,可能会找到多个符合条件的行。range使用索引选择行,只检索给定范围内的行。一般来说,索引字段是用来检索给定范围内的数据,通常出现在使用between...and、<、>、<=、in等条件查询的where语句中。index扫描全表索引,通常比ALL快。ALL全表扫描,MySQL遍历整个表寻找匹配的行,性能最差。6.possible_keys表示查询中可能使用的索引进行搜索,列出的索引不一定是最终查询数据中使用的索引。7.key和possible_keys是有区别的。key表示查询中实际使用的索引。如果没有使用索引,它将显示为NULL。8.key_len表示查询中使用的索引键的长度(字节数)。如果是单列索引,则计算整个索引长度。如果是联合索引,并不是所有的列都被使用,那么只会计算实际使用的列,所以可以根据key_len来判断联合索引是否有效。九、ref显示在索引列上用哪些列或常量来查找值。常用值有:const、func、null、字段名。10.rowsmysql估计需要读取的行数才能找到我们需要的记录。这个数据可以用来直观的展示SQL的性能。通常,行值越小越好。11、Filtered指的是返回的结果行数占需要读取的行数(rows列的值)的百分比。一般来说,越大越好。12.Extra表示附加信息。该字段可以为我们提供更多详细信息以了解执行计划。Usingindex表示select查询中使用了覆盖索引。覆盖索引的好处是一条SQL可以通过索引返回我们需要的数据。Usingwhere查询中没有使用索引,然后通过where条件过滤得到需要的数据。使用临时表是指在查询时,MySQL需要创建一个临时表来保存结果。临时表一般会影响性能,应该尽量避免。有时候使用DISTINCT去重也会产生Usingtemporary。使用filesort,我们知道索引除了可以起到查询的作用,排序也可以起到作用,所以当SQL中包含ORDERBY操作,而无法使用索引完成排序操作时,MySQL已经选择相应的排序算法来实现,这时候就会出现Usingfilesort,尽量避免Usingfilesort。综上所述,优化一条SQL语句的第一步就是要知道这条SQL语句需要优化什么。explainexecutionplan就像一面镜子,可以向开发者列出详细的执行状态。因此,利用好explain执行计划可以解决80%的SQL优化问题。在explain信息中,一般我们需要关心type,也就是level。如果是互联网公司,一般需要在range以上的level,然后我们关注Extra,有没有filesort或者usingtemplate。一旦出现,我们需要考虑一下。避免的方法就是看key用的是什么索引,过滤的屏蔽比是多少。本文到此结束。希望大家看完后能对SQL优化有更深入的了解。感谢您阅读。
