上篇文章《??MySQL性能调优,这个工具最有用(上)??》详细描述了explain结果中最重要的类型字段(连接类型)的含义。其实explain结果中有一个Extra字段,对SQL的分析和优化很有帮助。今天,我将花一分钟时间与您聊天。数据准备:createtableuser(idintprimarykey,namevarchar(20),sexvarchar(5),index(name))engine=innodb;insertintouservalues(1,'shenjian','no');insertintouservalues(2,'zhangsan','no');insertintouservalues(3,'lisi','yes');insertintouservalues(4,'lisi','no');数据说明:用户表:id主键索引,name普通索引(非唯一),sex无索引;四行记录:名字commonindex有重复记录lisi;实验目的:通过构造各种SQL语句解释explain的Extra字段,启发式定位低性能SQL语句进行优化。1、【Usingwhere】实验语句:说明select*fromuserwheresex='no';结果说明:Extra是Usingwhere的说明,SQL使用where条件过滤数据。需要注意的是,如果返回所有记录的SQL没有使用where条件过滤数据,那么很有可能达不到预期。这种类型的SQL经常需要优化;使用where条件的SQL并不代表不需要优化,往往需要配合explain结果中的类型(连接类型)来综合判断;画外音:加入类型在《上》中有详细介绍,本文不再展开。本例中Extra字段虽然表示使用了where条件过滤,但是type属性为ALL,表示需要扫描所有数据,仍有优化空间。一种常见的优化方法是在where过滤器属性上添加索引。画外音:本例中,sex字段差异化程度不高,加索引对性能提升有限。2、【使用索引】实验语句:说明selectid,namefromuserwherename='shenjian';结果说明:Extra是Usingindex的说明,SQL需要返回的所有列数据都在一个索引树中,不需要访问实际的行记录。画外音:仅使用索引树中的信息从表中检索列信息,而无需执行额外的查找以读取实际行。这样的SQL语句往往具有更好的性能。问题是,索引树中会包含什么样的列数据呢?3、【使用索引条件】实验语句:说明selectid,name,sexfromuserwherename='shenjian';画外音:这条SQL语句和前面的SQL语句的区别在于查询的列多了一个sex字段。结果描述:Extra是Usingindexcondition的描述,确实命中了索引,但并非所有列数据都在索引树中,需要访问实际的行记录。画外音:聚簇索引,和普通索引的底层实现区别,之前写过。这种SQL语句的性能也很高,但不如Usingindex。问题来了,如何针对Using索引进行优化呢?4、【Usingfilesort】实验语句:说明select*fromuserorderbysex;结果说明:Extra是Usingfilesort的说明,要得到需要的结果集,需要对所有记录进行排序。此类SQL语句性能极差,需要优化。通常,如果对未被索引的列执行orderby,则会触发filesort。一个常见的优化方案是在orderby的列上加一个索引,避免每次查询都全排序。5、【Usingtemporary】实验语句:说明select*fromusergroupbynameorderbysex;resultdescription:extra是Usingtemporary的说明,需要创建一个临时表来临时存放中间结果。此类SQL语句性能低下,经常需要优化。通常,当groupby和orderby同时存在并且作用于不同的字段时,会创建一个临时表来计算最终的结果集。6、【使用joinbuffer(BlockNestedLoop)】实验语句:解释select*fromuserwhereidin(selectidfromuserwheresex='no');结果说明:Extra是Usingjoinbuffer(BlockNestedLoop)的说明,需要进行嵌套循环计算。画外音:内层和外层的类型都是ALL,行数都是4,需要循环计算4*4次。这类SQL语句的性能往往很低,需要优化。通常,这发生在两个关联表被连接时,并且关联字段都没有索引。常见的优化方案是在关联字段上加索引,避免每次嵌套循环计算。结尾:explain是SQL优化中最常用的工具。type和extra完成后,explain就基本完成了。
