一直对SQL优化的技能心存无限的向往,以前面试的时候有不少面试官都会来一句,你会优化吗?我说我不太会,这时可能不少人就会有点儿说法了,好比会说不要使用通配符*去检索表、给经常使用的列创建索引、还有建立表的时候注意选择更优的数据类型去存储数据等等,我只能说那些都是常识,做为开发人员是必需要知道的。但真正的优化并非使用那些简单的手法去完成实现的,要想知道一条SQL语句执行效率低的缘由,咱们能够借助MySQL的一大神器---"EXPLAIN命令",EXPLAIN命令是查询性能优化不可缺乏的一部分,本文在结合实例的同时会总结explain命令的使用及相关参数的说明。面试
首先说说我此次浴火重生的优化初衷吧,上个月在公司完成的统计模块中,其中就有几条SQL语句执行的速度稍微有点慢,内心一直留了一道坎。直到昨天晚上在家看了一篇文章,是关于MySQL优化的对EXPLAIN命令的详解,因此今天一到公司就想着把以前那些SQL语句的病赶忙给看看,虽然,我没有达到那种秒查的效果,可是优化的效果仍是有明显的提高。性能优化
下面是我以前写的SQL语句(未优化前的),它执行的时间是2.318sec,而且使用EXPLAIN命令进行分析:性能
首先说说EXPLAIN命令查询后打印的数据列它们各个列表明的意思:学习
一、id :该列的值是用来顺序标识整个查询中SELELCT 语句的执行顺序,在嵌套查询中id越大的语句越先执行,该值可能为NULL。我的建议,能够在分析一条很长的SQL语句时能够依照它的值来按顺序进行切割分析优化。优化
二、select_type :表示当前select查询的类型,该列可能出现的值还有以下状况;spa
三、table :对应行正在访问哪个表,表名或者别名(注意:MySQL对待这些表和普通表同样,可是这些“临时表”是没有任何索引的);翻译
关联优化器会为查询选择关联顺序,左侧深度优先blog
当from中有子查询的时候,表名是derivedN的形式,N指向子查询,也就是explain结果中的下一列索引
当有union result的时候,表名是union 1,2等的形式,1,2表示参与union的query id开发
四、type :该列的值表明的含义是访问数据表的检索类型,也是最为重要的优化指标之一,它的好坏状况依次是 system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL ,通常来讲,得保证查询至少达到range级别,最好能达到ref级别,下面是各个值表明的意思。我的建议:能够在分析一条很长的SQL语句时,尽可能让每一个拆分的检索子句都到理想的优化级别;
五、possible_keys :显示查询使用了哪些索引,表示该索引能够进行高效地查找,可是列出来的索引对于后续优化过程多是没有用的,也就是说该索引在查找的时候未必真正的使用上。
六、key :该列表示在检索时实际决定使用的键(索引)。若是没有选择索引,键是NULL。要想强制MySQL使用或忽视possible_keys列中的索引,在查询中使用FORCE INDEX、USE INDEX或者IGNORE INDEX。
七、key_len :该列显示MySQL决定使用的键长度。若是键是NULL,则长度为NULL。使用的索引的长度。在不损失精确性的状况下,长度越短越好 。
八、ref :该列表示使用哪一个列或常数与key一块儿从表中选择行,我的翻译:就是当前检索中的语句与哪一个表中的列联合查找数据的。
九、rows :该列显示MySQL认为它执行查询时必须检查的行数。注意这是一个预估值。我的建议:该值若是比整表总记录数越低,则越好。
十、Extra :该列的值是EXPLAIN输出中另一个很重要的列,该列显示MySQL在查询过程当中的一些详细信息,MySQL查询优化器执行查询的过程当中对查询计划的重要补充信息。咱们一般根据该列的值来判断SQL语句是否须要优化;
我经过MySQL EXPLAIN分析的思路是这样的:一般首先要根据id的值肯定当前检索语句是什么时候执行的,注意分析的时候按顺序分析,其次在根据type列的值来判断当前检索语句是否须要优化,最后看决定性的一点就是根据Extra的值,上面表格中也说了,若是看到Using temporary通常就须要优化了。
由于我上面的那条语句是一个子查询,因此我首先根据id的值找到最早执行的检索语句,也就是嵌套在最内层的那条等值查询语句,它分别使用等值条件去链接企业表和上传数据表筛选出符合条件的数据,可是使用EXPLAIN命令分析得出,这条检索语句并非真正的高效,在扫描org表的时候进行了全表数据链接而不是有条件的去刷选链接,并且在等值链接的时候并未真正使用主键索引去等值链接,再回过头来仔细想一想咱们的业务,就是拿着info表中的数据去org表中进行匹配,固然全表扫描info是避免不了的,可是org表不必定所有都扫描啊,因此我试着用左链接替代以前的等值链接,果真效果达到了,info表进行了全表数据匹配去链接org表中的数据,而且在匹配的时候org表的主键索引也真正使用到了,级别达到了eq_ref,至于info表的ALL级别,毋庸置疑业务须要必须就是要去扫描整表的;最后看到最外层的检索语句也未必是高效的,它关联的地区表也进行了全表数据匹配,可是我要的查询结果是根据子查询结果来得出的,确定不比子查询结果的数据多,因此我将子查询结果做为左表去匹配地区表中的数据,果真,由ALL级别变成range级别,检查的行数也由3646减小到了15,通过分析优化执行速度提高1秒多,优化级别基本达到理想的状态,因为本人能力有限,只能作到这步: