最近作一个CRM系统,发现了慢查询日志里记载了许多的慢sql,因而就对其进行了sql优化。在优化的过程当中,本身也概括整理了一些sql优化的方案。今天就来和你们聊聊。html
**一、慢查询的分析**
常见的分析慢查询sql的方法大概有三种:explain、show profile、trace 分析 sql优化器。本文主要介绍explain的方法去分析慢sql,其他两种方法有兴趣的同窗能够去了解下。算法
**二、explain各参数解释**
(1)explain语法:explain+“需分析的sql”;
例:我想分析“select * from table1 where b=500;”这条sql的执行效率,那么直接在sql命令行下执行“expalin select * from table1 where b=500;”就能够查看了;执行结果以下:
根据上图,能够看到有许多个字段,那这些字段分别有什么意义呢?见下图(红框标出的为重点关注字段):
其中各个字段又可能有多个不一样的值,重点关注字段select_type、type、Extra的可能值以下图所示:
其中,上图中的“type”的值的查询性能从上到下依次是最好到最差。sql
**三、经常使用sql优化方法**数据库
(1)使用索引
你们对MySQL的索引应该不会感到陌生吧,数据量大的时候,最多见的加快查询效率的方法那确定是加索引了,要知道MySQL的B+索引树但是能在2~4层树就能从上亿的数据中提取出相关数据的,不加索引的话得进行上亿次磁盘io查找(关于B+树的具体原理,你们能够参考下这篇文章,写得很不错,http://www.liuzk.com/410.html。索引虽好用,可是存在不少不走索引的状况。下面列举常见几种不走索引的状况,以及如何让它走索引:
①对查询条件使用函数
如:select * from table1 where date(c) ='2020-08-20';
应改成:select * from table1 where c>='2020-08-20 00:00:00' and c<='2020-08-20 23:59:59';
②隐式转换:如把varchar类型当成int型去写
例:select * from table1 where a=1000; (其中,a字段在数据库中是varchar类型)
应改成:select * from table1 where a='1000';
③模糊查询
如:select * from table1 where a like '%1111%';
应改成:select * from table1 where a like '1111%'; 但要看具体业务,可能不对
注意:select * from table1 where a like '%1111'; 这种也是不走索引的
能够这么理解:like 匹配是%在前面的都不走索引
④范围查询
如:select * from table1 where b>=1 and b <=2000; (这条数据查询范围过大,是全表扫描,优化器选择不走索引)
应改成:select * from table1 where b>=1 and b <=1000;
select * from table1 where b>=1001 and b <=2000;
⑤计算操做 (但通常在代码层面作操做,不多会在数据库作操做)
如:select * from table1 where b-1 =1000;
应改成:select * from table1 where b =1000 + 1;
⑥OR 操做
若是条件中有OR,即便其中有条件带索引也不会使用。换言之,就是要求使用的全部字段,都必须创建索引。因此除非每一个列都创建了索引,不然不建议使用OR,在多列OR中,能够考虑用UNION 替换
如:select * from table1 where create_time = '2020-08-20 11:49:30' OR b > 854;
应改成:select * from table1 where create_time = '2020-08-20 11:49:30' UNION select * from table1 where b > 854;函数
(2)分页优化
如:select * from table1 order by a limit 99000,10; (其中,a字段有索引)
但结果不走索引,缘由是扫描整个索引并查找到没索引的行的成本比扫描全表的成本更高,因此优化器放弃使用索引。(关键是让排序时返回的字段尽量少)
应改成:select * from table1 f inner join (select id from table1 order by a limit 99000,10)g on f.id = g.id;
或者 select * from table1 where id >= (select id from table1 order by a limit 99000,1) limit 10;oop
(3)链接查询优化
在项目中,表链接查询是比较常见的,尤为是一些统计模块。表链接有两种算法,一种叫Nested-Loop Join 算法(简称NLJ),另外一种是Block Nested-Loop Join 算法(简称BNL)(关联字段不存在索引时会使用到)。感兴趣的小伙伴能够深刻去了解下相关原理哦。咱们进行关联查询优化的方法是:尽可能让 BNL变成 NLJ ,就是说在关联字段上加上索引。性能
(4)order by和group by优化
①首先咱们要知道MySQL中有两种排序方式,一种是经过有序索引直接返回有序数据(Extra字段:Using index);另外一种是经过 Filesort 进行的排序,不走索引(Extra字段:Using filesort);毫无疑问,确定是有序索引排序更快。
常见order by优化方法:
①在排序字段上添加索引
如:select c,id from table1 order by c; (c有索引)
②多个字段排序,能够在多个排序字段上添加联合索引来优化排序语句
如:select id,a,b from table1 order by a,b; (a,b是联合索引)
注意:select id,a,b from table1 order by b,a; (a,b是联合索引)此时不走索引,最左匹配前缀原则了解下
③对于先等值查询再排序的语句,能够经过在条件字段和排序字段添加联合索引来优化
如:select id,a,b from table1 where a=1000 order by b; (a,b是联合索引)
若是a,b不是联合索引的话,即时有a索引,b索引,排序也不会走索引
④去掉没必要要的返回字段
如:select * from table1 order by a,b; /* 根据a和b字段排序查出全部字段的值 */
应改成:select id,a,b from table1 order by a,b; /* 根据a和b字段排序查出id,a,b字段的值 */
不走索引缘由:扫描整个索引并查找到没索引的行的成本比扫描全表的成本更高,
因此优化器放弃使用索引。
默认状况,会对 group by 字段排序,所以group by优化方式与 order by 基本一致。优化
本篇文章就写到这,大家工做中还有什么好的优化sql的方法吗?欢迎在评论区分享!spa