
写SQL语句的时间我们每每关注的是SQL的履行效果,但是是否真的关注了SQL的履行服从,是否注重了SQL的写法标准?
以下的干货分享是在现实开辟过程中总结的,盼望对各人有所资助!
1. limit分页优化
当偏移量特殊大时,limit服从会非常低。
SELECT id FROM A LIMIT 1000,10 很快
SELECT id FROM A LIMIT 90000,10 很慢
方案一:
select id from A order by id limit 90000,10;
假如我们联合order by利用。很快,0.04秒就OK。 由于利用了id主键做索引!固然,是否可以或许利用索引还必要根据业务逻辑来定,这里只是为了提示各人,在分页的时间还需慎重利用!
方案二
select id from A order by id between 90000 and 90010;
2.使用limit 1 、top 1 取得一行
有些业务逻辑举行查询操纵时(特殊是在根据某一字段DESC,取最大一笔).可以利用limit 1 大概 top 1 来停止[数据库索引]继承扫描整个表或索引。
反例
SELECT id FROM A LIKE 'abc%'
正例
SELECT id FROM A LIKE 'abc%' limit 1
3. 任何环境都不要用 select * from table ,用详细的字段列表更换"*",不要返回用不到的字段,制止通盘扫描!
4. 批量插入优化
反例
INSERT into person(name,age) values('A',24)INSERT into person(name,age) values('B',24)INSERT into person(name,age) values('C',24)
正例
INSERT into person(name,age) values('A',24),('B',24),('C',24),
sql语句的优化首要在于对索引的精确利用,而我们在开辟中常常犯的错误便是对表举行通盘扫描,一来影响性能,而来消耗时间!
5.like语句的优化
反例
SELECT id FROM A WHERE name like '%abc%'
由于abc前面用了“%”,因此该查询一定走全表查询,除非须要(含糊查询必要包罗abc),否则不要在关键词前加%
正例
SELECT id FROM A WHERE name like 'abc%'
6.where子句利用 in 或 not in 的优化
sql语句中 in 和 not in 的利用请慎用!利用in 大概 not in 会抛弃索引,从而举行通盘扫描!
方案一:between 更换 in
反例
SELECT id FROM A WHERE num in (1,2,3)
正例
SELECT id FROM A WHERE num between 1 and 3
方案二:exist 更换 in
注:关于exist和in的用法,片尾有彩蛋~
反例
SELECT id FROM A WHERE num in (select num from B)
正例
SELECT num FROM A WHERE num exists (select 1 from B where B.num = A.num)
方案三:left join 更换 in
反例
SELECT id FROM A WHERE num in (select num from B)
正例
SELECT id FROM A LEFT JOIN B ON A.num = B.num
7.where子句利用or的优化
通常利用 union all 或 union 的方式更换“or”会得到更好的结果。where子句中利用了or关键字,索引将被放弃利用。
反例
SELECT id FROM A WHERE num = 10 or num = 20
正例
SELECT id FROM A WHERE num = 10 union all SELECT id FROM A WHERE num=20
8.where子句中利用 IS NULL 或 IS NOT NULL 的优化
反例
SELECT id FROM A WHERE num IS NULL
在where子句中利用 IS NULL 或 IS NOT NULL 判定,索引将被放弃利用,会举行全表查询。
正例
优化成num上设置默认值0,确保表中num没有null值, IS NULL 的用法在现实业务场景下SQL利用率极高,我们应注重制止全表扫描
SELECT id FROM A WHERE num=0
9.where子句中对字段举行表达式操纵的优化
不要在where子句中的“=”左侧举行函数、算数运算或其他表达式运算,否则体系将大概无法精确利用索引。
- 1
SELECT id FROM A WHERE datediff(day,createdate,'2019-11-30')=0
优化为
SELECT id FROM A WHERE createdate>='2019-11-30' and createdate<'2019-12-1'
- 2
SELECT id FROM A WHERE year(addate) <2020
优化为
SELECT id FROM A where addate<'2020-01-01'
10.排序的索引题目
mysql查询只是用一个索引,因此假如where子句中已利用了索引的话,那么order by中的列是不会利用索引。因此数据库默认排序可以符合要求环境下不要利用排序操纵;
只管不要包罗多个列的排序,假如必要最好给这些列创建复合索引。
11. 只管用 union all 更换 union
union和union all的差别首要是前者必要将两个(大概多个)效果集归并后再举行唯一性过滤操纵,这就会涉及到排序,增添大量的cpu运算,加大资源斲丧及耽误。以是当我们可以确认不大概出现重复效果集大概不在意重复效果集的时间,只管利用union all而不是union
12.Inner join 和 left join、right join、子查询
- 第一:inner join内毗连也叫等值毗连是,left/rightjoin是外毗连。
SELECT A.id,A.name,B.id,B.name FROM A LEFT JOIN B ON A.id =B.id;SELECT A.id,A.name,B.id,B.name FROM A RIGHT JOIN ON B A.id= B.id;SELECT A.id,A.name,B.id,B.name FROM A INNER JOIN ON A.id =B.id;
颠末来之多方面的证明 inner join性能比力快,由于inner join是等值毗连,大概返回的行数比力少。但是我们要记得有些语句隐形的用到了等值毗连,如:
SELECT A.id,A.name,B.id,B.name FROM A,B WHERE A.id = B.id;
保举:能用inner join毗连只管利用inner join毗连
- 第二:子查询的性能又比外毗连性能慢,只管用外毗连来更换子查询。
反例
mysql是先对外表A履行全表查询,然后根据uuid逐次履行子查询,假如外层表是一个很大的表,我们可以想象查询性能会体现比这个更加糟。
Select* from A where exists (select * from B where id>=3000 and A.uuid=B.uuid);
履行时间:2s摆布
正例
Select* from A inner join B ON A.uuid=B.uuid where b.uuid>=3000; 这个语句履行测试不到一秒;
履行时间:1s不到
- 第三:利用JOIN时间,应当用小的效果驱动大的效果
left join 左侧表效果只管小,假如有条件应当放到左侧先处置惩罚,right join同理反向。如:
反例
Select * from A left join B A.id=B.ref_id where A.id>10
正例
select * from (select * from A wehre id >10) T1 left join B on T1.id=B.ref_id;
13.exist 取代 in
反例
SELECT * from A WHERE id in ( SELECT id from B )
正例
SELECT * from A WHERE id EXISTS ( SELECT 1 from A.id= B.id )
分析:
in 是在内存中遍历比力
exist 必要查询数据库,以是当B的数据量比力大时,exists服从优于in**
in()只履行一次,把B表中的全部id字段缓存起来,以后查抄A表的id是否与B表中的id相称,假如id相称则将A表的记载参加到效果会合,直到遍历完A表的全部记载。
In 操纵的流程道理犹如一下代码
List resultSet={}; Array A=(select * from A); Array B=(select id from B); for(int i=0;i<A.length;i++) { for(int j=0;j<B.length;j++) { if(A[i].id==B[j].id) { resultSet.add(A[i]); break; } } } return resultSet;
可以看出,当B表数据较大时不得当利用in(),由于会把B表数据全部遍历一次
如:A表有10000条记载,B表有1000000条记载,那么最多有大概遍历10000*1000000次,服从很差。
再如:A表有10000条记载,B表有100条记载,那么最多有大概遍历10000*100次,遍历次数大大淘汰,服从大大提拔。
结论:in()得当B表比A表数据小的环境
exist()会履行A.length()次,履行过程代码如下
List resultSet={};Array A=(select * from A);for(int i=0;i<A.length;i++) { if(exists(A[i].id) { //履行select 1 from B where B.id=A.id是否有记载返回 resultSet.add(A[i]); }}return resultSet;
当B表比A表数据大时得当利用exists(),由于它没有那么多遍历操纵,只必要再履行一次查询就行。
如:A表有10000条记载,B表有1000000条记载,那么exists()会履行10000次去判定A表中的id是否与B表中的id相称。
如:A表有10000条记载,B表有100000000条记载,那么exists()照旧履行10000次,由于它只履行A.length次,可见B表数据越多,越得当exists()发挥结果。
再如:A表有10000条记载,B表有100条记载,那么exists()照旧履行10000次,还不如利用in()遍历10000*100次,由于in()是在内存里遍历比力,而exists()必要查询数据库,
我们都知道查询数据库所斲丧的性能更高,而内存比力很快。
结论:exists()得当B表比A表数据大的环境
说点什么...