责任编辑他们来聊聊工程项目中常用的MySQL强化形式,共19条,具体内容如下表所示:
1、EXPLAIN
做MySQL强化,他们要充分运用EXPLAIN查阅SQL继续执行方案。
上面来个单纯的实例,标示(1、2、3、4、5)他们要重
2、SQL句子中IN包涵的值不该过多
MySQL对IN做了适当的强化,将要IN中的自变量全数储存在两个字符串里头,所以那个字符串是排好序的。但是假如值非常多,造成的耗用也是较为大的。再比如:select id from t where num in(1,2,3) 对已连续的值,会用between就千万别用in了;再或是采用相连来代替。
3、SELECT句子亦须详述Hamming称
SELECT*减少许多无谓的耗用(CPU、IO、缓存、网络连接);增加了采用全面覆盖检索的几率;当表内部结构出现出现改变时,前断也须要预览。所以明确要求间接在select前面断开Hamming。
4、当只须要两条统计数据的时候,采用limit 1
这是为的是使EXPLAIN中type列达至const类别
5、假如排序字段没有用到检索,就尽量少排序
6、假如限制条件中其他字段没有检索,尽量少用or
or两边的字段中,假如有两个不是检索字段,而其他条件也不是检索字段,会造成该查询不走检索的情况。许多时候使用union all或是是union(必要的时候)的形式来代替“or”会得到更好的效果。
7、尽量用union all代替union
union和union all的差异主要是前者须要将结果集合并后再进行唯一性过滤操作,这就会涉及到排序,减少大量的CPU运算,加大资源耗用及延迟。当然,union all的前提条件是两个结果集没有重复统计数据。
8、不采用ORDER BY RAND()
select id from `dynamic` order by rand() limit 1000;
上面的SQL句子,可强化为:
select id from `dynamic` t1 join (select rand() * (select max(id) from `dynamic`) as nid) t2 on t1.id > t2.nidlimit 1000;
9、区分in和exists、not in和not exists
select * from 表A where id in (select id from 表B)
上面SQL句子相当于
select * from 表A where exists(select * from 表B where 表B.id=表A.id)
区分in和exists主要是造成了驱动顺序的出现改变(这是性能变化的关键),假如是exists,那么以外层表为驱动表,先被访问,假如是IN,那么先继续执行子查询。所以IN适合于外表大而内表小的情况;EXISTS适合于外表小而内表大的情况。
关于not in和not exists,推荐采用not exists,不仅仅是工作效率问题,not in可能存在逻辑问题。如何高效的写出两个替代not exists的SQL句子?
原SQL句子:
select colname … from A表 where a.id not in (select b.id from B表)
高效的SQL句子:
select colname … from A表 Left join B表 on where a.id = b.id where b.id is null
取出的结果集如下表所示图表示,A表不在B表中的统计数据:
10、采用合理的分页形式以提升分页的工作效率
select id,name from product limit 866613, 20
采用上述SQL句子做分页的时候,可能有人会发现,随着表统计数据量的减少,间接采用limit分页查询会越来越慢。
强化的形式如下表所示:可以取前一页的最大个字符的id,然后根据那个最大的id来限制下一页的起点。比如此列中,上一页最大的id是866612。SQL可以采用如下表所示的写法:
select id,name from product where id> 866612 limit 20
11、分段查询
在一些用户优先选择页面中,可能一些用户优先选择的时间范围过大,造成查询缓慢。主要的原因是扫描器个字符过多。那个时候可以通过程序,分段进行查询,循环遍历,将结果合并处理进行展示。
如下表所示图那个SQL句子,扫描器的个字符成百万级以上的时候就可以采用分段查询:
12、避免在where子句中对字段进行null值判断
对null的判断会导致引擎放弃采用检索而进行全表扫描器。
13、不建议采用%前缀模糊查询
比如LIKE“%name”或是LIKE“%name%”,这种查询会导致检索失效而进行全表扫描器。但是可以采用LIKE “name%”。
那如何查询%name%?
如下表所示图所示,虽然给secret字段添加了检索,但在explain结果并没有采用:
那么如何解决那个问题呢,答案:采用全文检索。
在他们查询中经常会用到select id,fnum,fdst from dynamic_201606 where user_name like %zhangsan%; 。这样的句子,普通检索是无法满足查询需求的。庆幸的是在MySQL中,有全文检索来帮助他们。
创建全文检索的SQL语法是:
ALTER TABLE `dynamic_201606` ADD FULLTEXT INDEX `idx_user_name` (`user_name`);
采用全文检索的SQL句子是:
select id,fnum,fdst from dynamic_201606 where match(user_name) against(zhangsan in boolean mode);
特别注意:在须要创建全文检索之前,请联系DBA确定能否创建。同时须要特别注意的是查询句子的写法与普通检索的区别。
14、避免在where子句中对字段进行表达式操作
比如:
select user_id,user_project from user_base where age*2=36;
中对字段就行了算术运算,这会造成引擎放弃采用检索,建议改成:
select user_id,user_project from user_base where age=36/2;
15、避免隐式类别转换
where子句中出现column字段的类别和传入的参数类别不一致的时候出现的类型转换,建议先确定where中的参数类别。
16、对联合检索来说,要遵守最左前缀法则
举列来说检索含有字段id、name、school,可以间接用id字段,也可以id、name这样的顺序,但是name;school都无法采用那个检索。所以在创建联合检索的时候一定要特别注意检索字段顺序,常用的查询字段放在最前面。
17、必要时可以采用force index来强制性查询走某个检索
有的时候MySQL强化器采行它认为合适的检索来检索SQL句子,但是可能它所采用的检索并不是他们想要的。这时就可以采用forceindex来强制性强化器采用他们制定的检索。
18、特别注意范围查询句子
对联合检索来说,假如存在范围查询,比如between、>、<等条件时,会造成前面的检索字段失效。
19、关于JOIN强化
LEFT JOIN A表为驱动表,INNER JOIN MySQL会自动找出那个统计数据少的表作用驱动表,RIGHT JOIN B表为驱动表。
特别注意:
1)MySQL中没有full join,可以用以下形式来解决:
select * from A left join B on B.name = A.namewhere B.name is nullunion allselect * from B;
2)尽量采用inner join,避免left join:
参与联合查询的表最少为2张表,一般都存在大小之分。假如相连形式是inner join,在没有其他过滤条件的情况下MySQL会自动优先选择小表作为驱动表,但是left join在驱动表的优先选择上遵循的是左边驱动右边的准则,即left join左边的表名为驱动表。
3)合理利用检索:
被驱动表的检索字段作为on的限制字段。
4)利用小表去驱动大表:
从原理图能够直观的看出假如能够减少驱动表的话,减少嵌套循环中的循环次数,以减少 IO总量及CPU运算的次数。
5)巧用STRAIGHT_JOIN:
inner join是由MySQL优先选择驱动表,但是有些特殊情况须要优先选择另个表作为驱动表,比如有group by、order by等「Using filesort」、「Using temporary」时。STRAIGHT_JOIN来强制性相连顺序,在STRAIGHT_JOIN左边的表名就是驱动表,右边则是被驱动表。在采用STRAIGHT_JOIN有个前提条件是该查询是内相连,也就是inner join。其他链接不推荐采用STRAIGHT_JOIN,否则可能造成查询结果不准确。
那个形式有时能减少3倍的时间。
以上19条MySQL强化形式希望对大家有所帮助!
原文地址:https://zhuanlan.zhihu.com/p/49888088