概述

今天主要分享下sqlserver数据库在做sql优化时的25条注意事项,仅供参考。


SQL优化事项

1、应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描,如:

 SELECT ID FROM T WHERE NUM IS NULL

可以在NUM上设置默认值0,确保表中NUM列没有NULL值,然后这样查询:

 SELECT ID FROM T WHERE NUM=0

2、应尽量避免在 where 子句中使用!=或<>操作符,否则将引擎放弃使用索引而进行全表扫描。优化器将无法通过索引来确定将要命中的行数,因此需要搜索该表的所有行;

3、应尽量避免在 where 子句中使用 OR来连接条件,否则将导致引擎放弃使用索引而进行全表扫描,如:

 SELECT ID FROM T WHERE NUM=10 OR NUM=20

可以这样查询:

 SELECT ID FROM T WHERE NUM=10 UNION ALL SELECT ID FROM T WHERE NUM=20

4、IN和 NOT IN 也要慎用,因为IN会使系统无法使用索引,而只能直接搜索表中的数据。如:

 SELECT ID FROM T WHERE NUM IN(1,2,3)

对于连续的数值,能用 BETWEEN就不要用 IN了,如:

 SELECT ID FROM T WHERE NUM BETWEEN 1 AND 3

5、尽量避免在索引过的字符数据中,使用非打头字母搜索。这也使得引擎无法利用索引。

见如下例子:

SELECT * FROM T1 WHERE NAME LIKE '%L%' ----> 无索引

SELECT * FROM T1 WHERE SUBSTING(NAME,2,1)='L' ----> 无索引

SELECT * FROM T1 WHERE NAME LIKE 'L%' ----> 有索引

即使NAME字段建有索引,前两个查询依然无法利用索引完成加快操作,引擎不得不对全表所有数据逐条操作来完成任务。而第三个查询能够使用索引来加快操作。

6、必要时强制查询优化器使用某个索引,如在 where 子句中使用参数,也会导致全表扫描。因为SQL只有在运行时才会解析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择的输入项。如下面语句将进行全表扫描:

 SELECT ID FROM T WHERE NUM=@NUM

可以改为强制查询使用索引:

 SELECT ID FROM T WITH(INDEX(索引名)) WHERE NUM=@NUM

7、应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而进行全表扫描。如:

 SELECT * FROM T1 WHERE F1/2=100 

应改为:

 SELECT * FROM T1 WHERE F1=100*2 SELECT * FROM RECORD WHERE SUBSTRING(CARD_NO,1,4)='5378'

应改为:

 SELECT * FROM RECORD WHERE CARD_NO LIKE '5378%' SELECT member_number, first_name, last_name FROM members  WHERE DATEDIFF(yy,datofbirth,GETDATE()) > 21 

应改为:

 SELECT member_number, first_name, last_name FROM members  WHERE dateofbirth < DATEADD(yy,-21,GETDATE()) 

即:任何对列的操作都将导致表扫描,它包括数据库函数、计算表达式等等,查询时要尽可能将操作移至等号右边。


8、应尽量避免在where子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行全表扫描。如:

select id from t where substring(name,1,3)='abc' ---->name以abc开头的id

select id from t where datediff(day,createdate,'2005-11-30')=0 ---->'2005-11-30'生成的id

应改为:

select id from t where name like 'abc%'

select id from t where createdate>='2005-11-30' and createdate

9、不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系统将可能无法正确使用索引。

10、在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽可能的让字段顺序与索引顺序相一致。

11、很多时候用 exists是一个好的选择,例:

 SELECT NUM FROM A WHERE NUM IN(SELECT NUM FROM B)

用下面的语句替换:

 SELECT NUM FROM A WHERE EXISTS(SELECT 1 FROM B WHERE NUM=A.NUM) SELECT SUM(T1.C1) FROM T1 WHERE(SELECT COUNT(*)FROM T2 WHERE T2.C2=T1.C2>0) 

用下面的语句替换:

 SELECT SUM(T1.C1) FROM T1WHERE EXISTS(SELECT * FROM T2 WHERE T2.C2=T1.C2) 

两者产生相同的结果,但是后者的效率显然要高于前者。因为后者不会产生大量锁定的表扫描或是索引扫描。

如果你想校验表里是否存在某条纪录,不要用count(*)那样效率很低,而且浪费服务器资源。可以用EXISTS代替。如:

 IF (SELECT COUNT(*) FROM table_name WHERE column_name = 'xxx') 

可以写成:

 IF EXISTS (SELECT * FROM table_name WHERE column_name = 'xxx')

经常需要写一个T_SQL语句比较一个父结果集和子结果集,从而找到是否存在在父结果集中有而在子结果集中没有的记录,如:

 SELECT a.hdr_key FROM hdr_tbl a ---- tbl a 表示tbl用别名a代替  WHERE NOT EXISTS (SELECT * FROM dtl_tbl b WHERE a.hdr_key = b.hdr_key)  SELECT a.hdr_key FROM hdr_tbl a  LEFT JOIN dtl_tbl b ON a.hdr_key = b.hdr_key WHERE b.hdr_key IS NULL  SELECT hdr_key FROM hdr_tbl  WHERE hdr_key NOT IN (SELECT hdr_key FROM dtl_tbl) 

三种写法都可以得到同样正确的结果,但是效率依次降低。


12、尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只有主键索引)。

13、避免频繁创建和删除临时表,以减少系统表资源的消耗。

14、临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

15、在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替 create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表的资源,应先create table,然后insert。

注意:SELECT INTO 语句会导致表锁定,阻止其他用户访问该表

16、如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先 truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

17、在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送 DONE_IN_PROC 消息。

18、尽量避免大事务操作,提高系统并发能力。

19、尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

20、避免使用不兼容的数据类型。例如float和int、char和varchar、binary和varbinary是不兼容的。数据类型的不兼容可能使优化器无法执行一些本来可以进行的优化操作。例如:

 SELECT name FROM employee WHERE salary > 60000 

在这条语句中,如salary字段是money型的,则优化器很难对其进行优化,因为60000是个整型数。我们应当在编程时将整型转化成为钱币型,而不要等到运行时转化。

21、充分利用连接条件,在某种情况下,两个表之间可能不只一个的连接条件,这时在 WHERE 子句中将连接条件完整的写上,有可能大大提高查询速度。

例:

 SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO  SELECT SUM(A.AMOUNT) FROM ACCOUNT A,CARD B WHERE A.CARD_NO = B.CARD_NO  AND A.ACCOUNT_NO=B.ACCOUNT_NO 

第二句将比第一句执行快得多。

22、使用视图加速查询

把表的一个子集进行排序并创建视图,有时能加速查询。它有助于避免多重排序操作,而且在其他方面还能简化优化器的工作。例如:

 SELECT cust.name,rcvbles.balance,……other columns  FROM cust,rcvbles  WHERE cust.customer_id = rcvlbes.customer_id  AND rcvblls.balance>0  AND cust.postcode>98000 ORDER BY cust.name

如果这个查询要被执行多次而不止一次,可以把所有未付款的客户找出来放在一个视图中,并按客户的名字进行排序:

 CREATE VIEW DBO.V_CUST_RCVLBES  AS  SELECT cust.name,rcvbles.balance,……other columns  FROM cust,rcvbles  WHERE cust.customer_id = rcvlbes.customer_id  AND rcvblls.balance>0  ORDER BY cust.name 

然后以下面的方式在视图中查询:

SELECT * FROM V_CUST_RCVLBES WHERE postcode>98000

视图中的行要比主表中的行少,而且物理顺序就是所要求的顺序,减少了磁盘I/O,所以查询工作量可以得到大幅减少。

23、能用DISTINCT的就不用GROUP BY

 SELECT OrderID FROM Details WHERE UnitPrice > 10 GROUP BY OrderID 

可改为:

 SELECT DISTINCT OrderID FROM Details WHERE UnitPrice > 10

24、能用UNION ALL就不要用UNION

UNION ALL不执行SELECT DISTINCT函数,这样就会减少很多不必要的资源

25、尽量不要用SELECT INTO语句

SELECT INOT 语句会导致表锁定,阻止其他用户访问该表。


上面我们提到的是一些基本的提高查询速度的注意事项,但是在更多的情况下,往往需要反复试验比较不同的语句以得到最佳方案。最好的方法当然是测试,看实现相同功能的SQL语句哪个执行时间最少,但是数据库中如果数据量很少,是比较不出来的,这时可以用查看执行计划,即:把实现相同功能的多条SQL语句考到查询分析器,按CTRL+L看查所利用的索引,表扫描次数(这两个对性能影响最大),总体上看询成本百分比即可。

觉得有用的朋友多帮忙转发哦!后面会分享更多devops和DBA方面的内容,感兴趣的朋友可以关注下~

怎么用sql按条件把表分离_在做sqlserver数据库sql优化时,这25条事项需要注意相关推荐

  1. sql replace替换多个字符_牛客网数据库SQL实战详细剖析(4150)

    文章来源:大数据肌肉猿 作者:无精疯 这是一个系列文章,总共61题,分6期,有答案以及解题思路,并附上解题的一个思考过程.具体题目可参考牛客网的SQL实战模块:https://www.nowcoder ...

  2. sql not exists用法_牛客网数据库SQL实战详细剖析(5160)(更新完结)

    文章来源:大数据肌肉猿 作者:无精疯 这是一个系列文章,总共61题,分6期,有答案以及解题思路,并附上解题的一个思考过程. 具体题目可参考牛客网的SQL实战模块: https://www.nowcod ...

  3. mysql世界国家数据库_世界国家 的数据库sql

    insert into lz_countries(no, title, code) values(1, '中国', 'CHINA'); insert into lz_countries(no, tit ...

  4. ::在sql语句中是什么写法_不懂就问:SQL 语句中 where 条件后 写上1=1 是什么意思...

    程序员在编程过程中,经常会在代码中使用到"where 1=1",这是为什么呢? SQL注入 初次看到这种写法的同学肯定很纳闷,加不加where 1=1,查询不都一样吗?例如: se ...

  5. oracle表结构修改回滚,87.Oracle数据库SQL开发之 修改表内存——数据库事务的提交和回滚...

    87.Oracle数据库SQL开发之 修改表内存--数据库事务的提交和回滚 数据库事务(transaction)就是一组SQL语句,这组SQL语句时一个逻辑工作单元. 要永久性的记录事务中SQL语句的 ...

  6. sql server 怎么把视图中的数据存到另外一张表中_承上篇,自制插件优化Kep数据存储问题...

    序言:上篇说到Kep数据日志存储是将所有数据存到一张表内,不好筛选,为此抽空做了这个插件对Kep存到SQL的数据表进行优化处理. 一.插件安装及界面功能标注 1.双击安装包弹出安装向导,直接下一步直到 ...

  7. mysql水果表查询_最全MySQL数据库表的查询操作

    序言 本节比较重要,对数据表数据进行查询操作,其中可能大家不熟悉的就对于INNER JOIN(内连接).LEFT JOIN(左连接).RIGHT JOIN(右连接)等一些复杂查询. 通过本节的学习,可 ...

  8. java sql 查询中的转义序列不对_在 JDBC 中使用 SQL 转义序列 - SQL Server | Microsoft Docs...

    使用 SQL 转义序列Using SQL escape sequences 08/12/2019 本文内容 按照 JDBC API 的定义,Microsoft JDBC Driver for SQL ...

  9. sql limit不接具体数字_这21个写SQL的好习惯,你要养成呀

    前言 每一个好习惯都是一笔财富,本文分SQL后悔药, SQL性能优化,SQL规范优雅三个方向,分享写SQL的21个好习惯,谢谢阅读,加油哈~ 公众号:「捡田螺的小男孩」 1. 写完SQL先explai ...

  10. db2 sql 判断select是否为空_学会复杂一点的SQL语句:Oracle DDL和DML

    create:创建表创建用户创建视图 创建表 create table student(id int,score int) ; student后面与括号之间可以有空格可以没有 创建用户 create ...

最新文章

  1. 为什么有时打不开爬取到的图片
  2. 粗题⼈不考你没学过的算法
  3. 小苏打到底能不能碱化尿液
  4. linux系统普通用户ssh不能登陆,关于CentOS普通用户无法登录SSH问题
  5. 前端学习(2957):组件之间的参数传递父传子
  6. 载 Kubernetes和OpenStack到底是什么关系?先搞清楚,再系列学习
  7. 计算机二级考试word论文,office二级考试之word
  8. OSChina 周六乱弹 ——致敬默默守护国运的男人们
  9. 计算机视觉之目标检测(object detection)《1》
  10. 2022-08-23:以下go语言代码输出什么?A:map[baz:2 foo:0];B:map[bar:1 baz:2];C:map[baz:2];D:不确定。 package main impo
  11. Win7与Win10在局域网内共享打印机
  12. 如果更好的做好MES系统运维
  13. idea 全局查找快捷键
  14. HTML基本页面模板
  15. 算法与数据结构(第一周)——线性查找法
  16. PADS Logic中单个器件的PCB封装应该怎么处理呢?
  17. 【C语言】sizeof常量字符串
  18. D1. Remove the Substring (从easy到hard)
  19. 雷神台式计算机配置,雷神电脑BIOS设置教程
  20. 人到中年,奋斗了十几年结果却是负债累累,还要继续创业吗?

热门文章

  1. RocketMQ开发指导之四——RocketMQ常见问题
  2. Vert.x Web
  3. 12通过作用域链实现闭包
  4. 优化器——梯度下降优化算法综述
  5. 【面向工业界】京东NLP算法工程师培养计划
  6. 【ICLR2021必读】 【自监督学习】 【Transformer】相关论文
  7. 【综述】详解ERNIE-Baidu进化史及应用场景
  8. 【GNN】一文轻松了解Graph Neural Networks
  9. 【论文笔记】中文词向量论文综述(一)
  10. 分治法经典问题-逆序对个数