SQL优化 MySQL版 - 单表优化及细节详讲

单表优化及细节详讲

做者 : Stanley 罗昊html

转载请注明出处和署名,谢谢!

注:本文章须要MySQL数据库优化基础或观看前几篇文章,传送门:mysql

B树索引详讲(初识SQL优化,认识索引):https://www.cnblogs.com/StanleyBlogs/p/10413349.htmlsql

B树索引进阶(索引分类、建立方式、删除索引、查看索引、SQL性能问题):https://www.cnblogs.com/StanleyBlogs/p/10416865.html数据库

SQL执行计划于笛卡尔积(了解什么是SQL执行计划,优化原理):https://www.cnblogs.com/StanleyBlogs/p/10422202.html工具

Type详讲(理解优化级别):https://www.cnblogs.com/StanleyBlogs/p/10426385.htmlpost

Extra(理解最终优化概念):https://www.cnblogs.com/StanleyBlogs/p/10429969.html性能

优化准备

首先咱们须要有一个数据库,bookdb,还要有一张数据表book,有如下字段,咱们接下来将用如下这张表来作优化实例;测试

单表优化

这次教程再也不使用可视化工具,由于效率太慢,我仍是比较喜欢命令行操做;优化

下面咱们须要编写如下条件的SQL语句:spa

查询authorid = 1而且 typeid为2或3的bid再根据typeid排序

SQL语句:select bid from book where typeid in (2,3) And authorid = 1 order by typeid desc;

咱们执行这条SQL语句,而后在前面加上explatin查看sql执行计划:

咱们能够清楚的看到,查询级别是ALL,而且Useing where回表查询了而且后面还有一个Using filesort表示建立临时表了,可见此条SQL语句是多么的恐怖,效率极低

这个时候咱们就来给它加个索引吧,毕竟都知道,加索引能够提升效率,那咱们就来分析一下以上这个sql语句;

首先该语句里面有 bid typeid authorid这三个字段,那么接下来我将给它们建立一个复合索引:

索引名我起名为idx_bta表明它的顺序 b 表明 bid t 表明 typeid a 就表明authorid;

加上索引后,咱们再执行一下,看看咱们这条sql语句有没有被优化:

首先,咱们能够看见,type级别被优化了一些,到了index了,也就是ALL的上一个级别,我在以前的文章也说过,最好优化到ref级别,可见咱们如今这条SQL仍是不够优化,而且 咱们后面还有Using filesirt,可是出现了Using index,说明仍是优化了一些,可是远远不够!

那么为何呢?我明明加了索引,它竟然还性能这么差?

原来,咱们忽略了一点,就是SQL解析过程

我在前几篇文章重点说过,编写过程,解析过程是不同的:

编写过程: 

select from join on where 条件 group by 分组 having过滤组 order by排序 limit限制查询个数

解析过程:

from on join where group by having select order by limit 

以上就是mysql的解析过程,咱们发现,跟咱们编写的过程彻底不一致!

也就是说,咱们尽管bid在前面,typeid跟authorid在后面,可是它实际执行的时候倒是先执行where(type、authorid),而不是select(bid);

可是咱们索引顺序是怎么建的?

是 b t a 的顺序(bid typeid authorid),既然where我如今非要先让bid先执行,很显然不知足最佳左前缀,就是从左向右依次执行,我如今的索引并无知足,由于我如今却让最右边的先执行了(bid)

因此,咱们须要改变一下索引的顺序,既然先解析where,我就让where后面的俩字段放在前面(typeid authorid),把select放在后面(bid);

根据SQL实际解析的顺序,调整索引的顺序;

在创建这个索引以前,咱们务必删掉没用的索引

删掉后,咱们把索引的顺序改变一下,以前是 b t a 如今我改为 t a b(typeid authorid bid);

添加索引后,我而且查询索引,发现建立成功了,咱们再运行一下试试,此次我改变了索引顺序,顺序按照解析顺序排列,看看此次的效果如何:

咱们发现,type等级仍然是index,由于没有建立临时表了也就是额外的查询,性能明显提高了,可是咱们的type等级还是index,确实尚未达到咱们想要的ref标准,接下来咱们继续优化;

咱们如今开始重点优化索引级别,很显然,咱们的索引级别是index,距离ref还有点距离;

再次优化

system>const>eq_ref>ref>range>index>ALL

很明显啊,咱们如今的这条sql才到index级别,我以前说过,最好达到ref或range级别;

咱们来把以前的SQL拿过来:

 select bid from book where typeid in (2,3) And authorid = 1 order by typeid desc;

我如今将where条件后面这两个字段换一个顺序,为啥换顺序呢,看这个in

我以前讲过范围查询,in是有可能致使索引失效的,从而转为无索引;

我如今思路是,若是in失效了或typeid失效了,那你authorid也就跟着一块儿失效了,为何呢?

咱们来看一下索引顺序,咱们是先typeid 后 authorid,若是你typeid都没了,那么authorid也可能也受干扰了,因此我把它顺序换换;

alter table book add index idx_atb(authorid,typeid,bid);

我如今让它先authorid后typeid,那若是先a 后 t 那便是你 t 失效了,无所谓啊,我先a,a你也用了,这是个思路;

既然typeid会失效,那咱们改变一下where后面的顺序吧,既然你可能会失效,就把它日后放,别影响别人

explain select bid from book where authorid = 1 And typeid in (2,3) order by typeid desc;

务必也把索引顺序也更改一下!

alter table book add index idx_atb(authorid,typeid,bid);

咱们改变索引顺序跟SQL语句where后面的顺序后再执行:

咱们再查看type级别会发现已经达到了fef级别,而且也有Using index,可是还有Using where

由于我typeid虽然也有索引,可是我使用了in,就索引失效了就跟typeid没有索引同样,这样就形成了又须要回原表查了,因此尽可能避免使用in;

小结:之因此这条SQL语句能达到了ref,是由于我知足了最佳左前缀,跟处理了索引失效的问题,既然你要失效,我就不要让你影响后面的字段,我就把你日后排,尽管你失效了,你不影响前面的,因此我把SQL语句where后面的两个字段换了位置;

索引须要逐步优化,要实时查询sql执行计划,采起逐步优化措施;

补充

刚刚在上方我把SQL语句字段where后面的字段调换了位置,而且索引也跟着调换了,其实通过测试,其实SQL语句无需调换,仅需调换索引位置便可:

今日感悟:

在你看不见的地方,总有你想不到的辛酸;

相关文章
相关标签/搜索