一、引言
数据库查询效率的快慢往往是评价一个数据库是好是差其中的一个标准。对于好的数据库而言,往往离不开良好的数据库设计,硬件配置,网络等诸多因数。那么我们在日常开发中,提高数据库查询效率最简单可行的方式就是优化sql语句。
查询速度慢的原因很多,常见如下几种
- 没有索引或者没有用到索引(这是查询慢最常见的问题,是程序设计的缺陷)
- I/O吞吐量小,形成了瓶颈效应
- 没有创建计算列导致查询不优化
- 内存不足
- 网络速度慢
- 查询出的数据量过大(可以采用多次查询,其他的方法降低数据量)
- 锁或者死锁(这也是查询慢最常见的问题,是程序设计的缺陷)
- sp_lock,sp_who,活动的用户查看,原因是读写竞争资源。
- 返回了不必要的行和列
- 查询语句不好,没有优化
1、操作符优化
1.1、IN、NOT IN 操作符
IN和EXISTS 性能有外表和内表区分的,但是在大数据量的表中推荐用EXISTS 代替IN 。Not IN 不走索引的是绝对不能用的,可以用NOT EXISTS 代替
1.2、IS NULL 或IS NOT NULL操作
索引是不索引空值的,所以这样的操作不能使用索引,可以用其他的办法处理,例如:数字类型,判断大于0,字符串类型设置一个默认值,判断是否等于默认值即可
1.3、<> 操作符(不等于)
不等于操作符是永远不会用到索引的,因此对它的处理只会产生全表扫描。 用其它相同功能的操作运算代替,如 a<>0 改为 a>0 or a<0 a<>’’ 改为 a>’’
1.4、用全文搜索搜索文本数据,取代like搜索
全文搜索始终优于like搜索:
(1)全文搜索让你可以实现like不能完成的复杂搜索,如搜索一个单词或一个短语,搜索一个与另一个单词或短语相近的单词或短语,或者是搜索同义词;
(2)实现全文搜索比实现like搜索更容易(特别是复杂的搜索);
1.5、优先使用union all ,避免使用union
UNION 因为会将各查询子集的记录做比较,故比起UNION ALL ,通常速度都会慢上许多。一般来说,如果使用UNION ALL能满足要求的话,务必使用UNION ALL。还有一种情况,如果业务上能够确保不会出现重复记录
2、SQL语句优化
2.1、select *
为什么不能使用,地球人都知道,但是很多人都习惯这样用,要明白能省就省,而且这样查询数据库不能利用“覆盖索引”了
2.2、尽量写WHERE子句
尽量不要写没有WHERE的SQL语句
2.3、注意SELECT INTO后的WHERE子句
因为SELECT INTO把数据插入到临时表,这个过程会锁定一些系统表,如果这个WHERE子句返回的数据过多或者速度太慢,会造成系统表长期锁定,诸塞其他进程。
2.4、对于聚合查询,可以用HAVING子句进一步限定返回的行
2.5、避免使用临时表
- 除非却有需要,否则应尽量避免使用临时表,相反,可以使用表变量代替;
- 大多数时候(99%),表变量驻扎在内存中,因此速度比临时表更快,临时表驻扎在TempDb数据库中,因此临时表上的操作需要跨数据库通信,速度自然慢。
2.6、减少访问数据库的次数:
程序设计中最好将一些常用的全局变量表放在内存中或者用其他的方式减少数据库的访问次数
2.7、尽量少做重复的工作
尽量减少无效工作,但是这一点的侧重点在客户端程序,需要注意的如下:
- 控制同一语句的多次执行,特别是一些基础数据的多次执行是很多程序员很少注意的
- 减少多次的数据转换,也许需要数据转换是设计的问题,但是减少次数是程序员可以做到的。
- 杜绝不必要的子查询和连接表,子查询在执行计划一般解释成外连接,多余的连接表带来额外的开销。
- 合并对同一表同一条件的多次UPDATE,比如
UPDATE EMPLOYEE SET FNAME=’HAIWER’ WHERE EMP_ID=’ VPA30890F’
UPDATE EMPLOYEE SET LNAME=’YANG’ WHERE EMP_ID=’VPA30890F’
-- 这两个语句应该合并成以下一个语句
UPDATE EMPLOYEE SET FNAME=’HAIWER’,LNAME=’YANG’ WHERE EMP_ID=’ VPA30890F’
- UPDATE操作不要拆成DELETE操作+INSERT操作的形式,虽然功能相同,但是性能差别是很大的。
- 不要写一些没有意义的查询,比如
SELECT * FROM EMPLOYEE WHERE 1=2
3、where使用原则
3.1、最具限制性的条件放在最前面
- 在下面两条select语句中:
select * from table1 where field1<=10000 and field1>=0;
select * from table1 where field1>=0 and field1<=10000;
如果数据表中的数据field1都>=0,则第一条select语句要比第二条select语句效率高的多,因为第二条select语句的第一个条件耗费了大量的系统资源。
3.2、字段的顺序应和索引中字段顺序一致
在下面的select语句中:
select * from tab where a=… and b=… and c=…;
若有索引index(a,b,c),则where子句中字段的顺序应和索引中字段顺序一致。
3.3、有索引的时候 >= 比 >快
select field3,field4 from tb where field1>=‘sdf’ 快
select field3,field4 from tb where field1>‘sdf’ 慢
因为前者快速定位索引。
3.3、like的用法
select field3,field4 from tb where field2 like ‘R%’ 快
select field3,field4 from tb where field2 like ‘%R’ 慢,
因为后者不使用索引。
3.4、函数
select field3,field4 from tb where upper(field2)='RMN’不使用索引。
如果一个表有两万条记录,建议不使用函数;如果一个表有五万条以上记录,严格禁止使用函数!两万条记录以下没有限制。