很多人不知道SQL语句在SQL SERVER中是如何执行的,他们担心自己所写的SQL语句会被SQL SERVER误解。比如:

select * from table1 where name='zhangsan' and tID > 10000

和执行:

select * from table1 where tID > 10000 and name='zhangsan'

一些人不知道以上两条语句的执行效率是否一样,因为如果简单的从语句先后上看,这两个语句的确是不一样,如果tID是一个聚合索引,那么后一句仅仅从表的10000条以后的记录中查找就行了;而前一句则要先从全表中查找看有几个name='zhangsan'的,而后再根据限制条件条件tID>10000来提出查询结果。
  事实上,这样的担心是不必要的。SQL SERVER中有一个“查询分析优化器”,它可以计算出where子句中的搜索条件并确定哪个索引能缩小表扫描的搜索空间,也就是说,它能实现自动优化。
  虽然查询优化器可以根据where子句自动的进行查询优化,但大家仍然有必要了解一下“查询优化器”的工作原理,如非这样,有时查询优化器就会不按照您的本意进行快速查询。
  在查询分析阶段,查询优化器查看查询的每个阶段并决定限制需要扫描的数据量是否有用。如果一个阶段可以被用作一个扫描参数(SARG),那么就称之为可优化的,并且可以利用索引快速获得所需数据。
  SARG的定义:用于限制搜索的一个操作,因为它通常是指一个特定的匹配,一个值得范围内的匹配或者两个以上条件的AND连接。形式如下:

列名 操作符 <常数 或 变量>

<常数 或 变量> 操作符列名列名可以出现在操作符的一边,而常数或变量出现在操作符的另一边。如:

Name='张三'

价格>5000

5000<价格

Name='张三' and 价格>5000  

如果一个表达式不能满足SARG的形式,那它就无法限制搜索的范围了,也就是SQL SERVER必须对每一行都判断它是否满足WHERE子句中的所有条件。所以一个索引对于不满足SARG形式的表达式来说是无用的。

介绍完SARG后,我们来总结一下使用SARG以及在实践中遇到的和某些资料上结论不同的经验:

1、Like语句是否属于SARG取决于所使用的通配符的类型

--如:
name like '张%' --,这就属于SARG

--而:
name like '%张' --,就不属于SARG。

原因是通配符%在字符串的开通使得索引无法使用。

2、or 会引起全表扫描
  Name='张三' and 价格>5000 符号SARG,而:Name='张三' or 价格>5000 则不符合SARG。使用or会引起全表扫描。

3、非操作符、函数引起的不满足SARG形式的语句
  不满足SARG形式的语句最典型的情况就是包括非操作符的语句,如:NOT、!=、<>、!<、!>、NOT EXISTS、NOT IN、NOT LIKE等,另外还有函数。下面就是几个不满足SARG形式的例子:

ABS(价格)<5000

Name like '%三'

--有些表达式,如:

WHERE 价格*2>5000

--SQL SERVER也会认为是SARG,SQL SERVER会将此式转化为:
WHERE 价格>2500/2

但我们不推荐这样使用,因为有时SQL SERVER不能保证这种转化与原始表达式是完全等价的。

4、IN 的作用相当与OR

语句:

Select * from table1 where tid in (2,3)

--和

Select * from table1 where tid=2 or tid=3

是一样的,都会引起全表扫描,如果tid上有索引,其索引也会失效。

5、尽量少用NOT

6、exists 和 in 的执行效率是一样的
  很多资料上都显示说,exists要比in的执行效率要高,同时应尽可能的用not exists来代替not in。但事实上,我试验了一下,发现二者无论是前面带不带not,二者之间的执行效率都是一样的。因为涉及子查询,我们试验这次用SQL SERVER自带的pubs数据库。运行前我们可以把SQL SERVER的statistics I/O状态打开:

(1)
select title,price from titles where title_id in (select title_id from sales where qty>30)

该句的执行结果为:

表 'sales'。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。
表 'titles'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

(2)
select title,price from titles
  where exists (select * from sales
  where sales.title_id=titles.title_id and qty>30)

第二句的执行结果为:

表 'sales'。扫描计数 18,逻辑读 56 次,物理读 0 次,预读 0 次。
表 'titles'。扫描计数 1,逻辑读 2 次,物理读 0 次,预读 0 次。

我们从此可以看到用exists和用in的执行效率是一样的。

7、用函数charindex()和前面加通配符%的LIKE执行效率一样
  前面,我们谈到,如果在LIKE前面加上通配符%,那么将会引起全表扫描,所以其执行效率是低下的。但有的资料介绍说,用函数charindex()来代替LIKE速度会有大的提升,经我试验,发现这种说明也是错误的:

select gid,title,fariqi,reader from tgongwen
   where charindex('刑侦支队',reader)>0 and fariqi>'2004-5-5'

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。

select gid,title,fariqi,reader from tgongwen
   where reader like '%' + '刑侦支队' + '%' and fariqi>'2004-5-5'

用时:7秒,另外:扫描计数 4,逻辑读 7155 次,物理读 0 次,预读 0 次。

8、union并不绝对比or的执行效率高
  我们前面已经谈到了在where子句中使用or会引起全表扫描,一般的,我所见过的资料都是推荐这里用union来代替or。事实证明,这种说法对于大部分都是适用的。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen
   where fariqi='2004-9-16' or gid>9990000

用时:68秒。扫描计数 1,逻辑读 404008 次,物理读 283 次,预读 392163 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where gid>9990000

用时:9秒。扫描计数 8,逻辑读 67489 次,物理读 216 次,预读 7499 次。

看来,用union在通常情况下比用or的效率要高的多。

但经过试验,笔者发现如果or两边的查询列是一样的话,那么用union则反倒和用or的执行速度差很多,虽然这里union扫描的是索引,而or扫描的是全表。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen
   where fariqi='2004-9-16' or fariqi='2004-2-5'

用时:6423毫秒。扫描计数 2,逻辑读 14726 次,物理读 1 次,预读 7176 次。

select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-9-16'
union
select gid,fariqi,neibuyonghu,reader,title from Tgongwen where fariqi='2004-2-5'

用时:11640毫秒。扫描计数 8,逻辑读 14806 次,物理读 108 次,预读 1144 次。

9、字段提取要按照“需多少、提多少”的原则,避免“select *”

  我们来做一个试验:

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
用时:4673毫秒
select top 10000 gid,fariqi,title from tgongwen order by gid desc
用时:1376毫秒
select top 10000 gid,fariqi from tgongwen order by gid desc
用时:80毫秒

由此看来,我们每少提取一个字段,数据的提取速度就会有相应的提升。提升的速度还要看您舍弃的字段的大小来判断。

10、count(*)不比count(字段)
  某些资料上说:用*会统计所有列,显然要比一个世界的列名效率低。这种说法其实是没有根据的。我们来看:

select count(*) from Tgongwen
用时:1500毫秒

select count(gid) from Tgongwen
用时:1483毫秒

select count(fariqi) from Tgongwen
用时:3140毫秒

select count(title) from Tgongwen
用时:52050毫秒

从以上可以看出,如果用count(*)和用count(主键)的速度是相当的,而count(*)却比其他任何除主键以外的字段汇总速度要快,而且字段越长,汇总的速度就越。我想,如果用count(*), SQL SERVER可能会自动查找最小字段来汇总的。当然,如果您直接写count(主键)将会来的更直接些。

11、order by按聚集索引列排序效率最高
  我们来看:(gid是主键,fariqi是聚合索引列):

select top 10000 gid,fariqi,reader,title from tgongwen

用时:196 毫秒。 扫描计数 1,逻辑读 289 次,物理读 1 次,预读 1527 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid asc

用时:4720毫秒。 扫描计数 1,逻辑读 41956 次,物理读 0 次,预读 1287 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by gid desc
用时:4736毫秒。 扫描计数 1,逻辑读 55350 次,物理读 10 次,预读 775 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi asc
用时:173毫秒。 扫描计数 1,逻辑读 290 次,物理读 0 次,预读 0 次。

select top 10000 gid,fariqi,reader,title from tgongwen order by fariqi desc
用时:156毫秒。 扫描计数 1,逻辑读 289 次,物理读 0 次,预读 0 次。

从以上我们可以看出,不排序的速度以及逻辑读次数都是和“order by 聚集索引列” 的速度是相当的,但这些都比“order by 非聚集索引列”的查询速度是快得多的。
  同时,按照某个字段进行排序的时候,无论是正序还是倒序,速度是基本相当的。

12、高效的TOP
  事实上,在查询和提取超大容量的数据集时,影响数据库响应时间的最大因素不是数据查找,而是物理的I/0操作。如:

select top 10 * from (
select top 10000 gid,fariqi,title from tgongwen
where neibuyonghu='办公室'
order by gid desc) as a
order by gid asc

这条语句,从理论上讲,整条语句的执行时间应该比子句的执行时间长,但事实相反。因为,子句执行后返回的是10000条记录,而整条语句仅返回10条语句,所以影响数据库响应时间最大的因素是物理I/O操作。而限制物理I/O操作此处的最有效方法之一就是使用TOP关键词了。TOP关键词是SQL SERVER中经过系统优化过的一个用来提取前几条或前几个百分比数据的词。经笔者在实践中的应用,发现TOP确实很好用,效率也很高。但这个词在另外一个大型数据库ORACLE中却没有,这不能说不是一个遗憾,虽然在ORACLE中可以用其他方法(如:rownumber)来解决。在以后的关于“实现千万级数据的分页显示存储过程”的讨论中,我们就将用到TOP这个关键词。

到此为止,我们上面讨论了如何实现从大容量的数据库中快速地查询出您所需要的数据方法。当然,我们介绍的这些方法都是“软”方法,在实践中,我们还要考虑各种“硬”因素,如:网络性能、服务器的性能、操作系统的性能,甚至网卡、交换机等。

转载于:https://www.cnblogs.com/firstdream/p/6085462.html

SQL Server中的SQL语句优化与效率问题相关推荐

  1. 【转】在SQL Server中通过SQL语句实现分页查询

    在SQL Server中通过SQL语句实现分页查询 2008年01月06日 星期日 12:28 建立表: CREATE TABLE [TestTable] ( [ID] [int] IDENTITY ...

  2. 在SQL Server中使用SQL Coalesce函数

    This article explores the string manipulation using SQL Coalesce function in SQL Server. 本文探讨了在SQL S ...

  3. 在SQL Server中插入IN-T-SQL语句

    In this article, we will go deeply through the INSERT INTO statement by showing the different syntax ...

  4. 如何从SQL Server中的SELECT语句更新

    In this article, we will learn different methods that are used to update the data in a table with th ...

  5. 如何在SQL Server中创建SQL依赖关系图

    Deleting or changing objects may affect other database objects like views or procedures that depends ...

  6. 转储sql文件_在Linux上SQL Server中更改SQL转储文件位置

    转储sql文件 In this article, we will talk about SQL Dump files and the process to change the dump direct ...

  7. sql server中的hash应用优化

    sql server很多地方用到hash,计划缓存查找,hash连接,hash聚合等. hash查找mssql很多设计中都应用了,不过我们能在开发设计中,也可以利用这个特性. 将如果有需求对大文本进行 ...

  8. 如何在sql存储过程中打log_SQL语句优化

    如何定位并优化慢查询 SQL?大致思路如下: 根据慢查询日志定位慢查询 SQL: 使用 explain 等工具分析 SQL: 修改 SQL 或者尽量让 SQL 走索引. 获取有性能问题的 SQL 的 ...

  9. 将一个基于磁盘的表迁移到SQL Server中的一个内存优化的表

    本文是微软的译文,对应的原文是:https://www.red-gate.com/simple-talk/sql/database-administration/migrating-disk-base ...

最新文章

  1. java soap协议头_java – 服务器无法识别HTTP标头“SOAPAction”的值
  2. 独家 | 支持向量机背后的数学 -对于SVM背后的数学和理论解释的快速概览及如何实现...
  3. SAP RETAIL 通过分配表创建UB STO单据
  4. 咨询公司建议完美批准私有化
  5. 目录:SpringBoot学习目录
  6. RESTful Web 服务 - 无状态
  7. IBM服务器系统盘更换后检查,IBM服务器更换rootvg故障磁盘操作指南
  8. 起点海外版 Hybrid App-内嵌页优化实践
  9. java 集合迭代器_Java中的集合迭代器
  10. JavaScript学习笔记(四)--复杂数据类型Object
  11. mysql连表查询效率,我就不信你还听不明白了!
  12. ubuntu apt-get 遇到的问题
  13. 嗯,手搓一个TinyPng压缩图片的WebpackPlugin也SoEasy啦
  14. 关于交流半波与全波整流输出的电压(或电流)有效值和平均值的讨论
  15. 注册微信小程序并开通微信支付流程
  16. 南京邮电大学嵌入式系统开发实验5:嵌入式Linux下LED报警灯驱动设计及编程
  17. ICC 图文学习——LAB2:Design Planning 设计规划
  18. [buuctf]ciscn_2019_ne_5
  19. Ubuntu Linux 双网卡 局域网 共享上网 很简单的操作
  20. 微型计算机组装的目的,微机组装实训报告范文

热门文章

  1. 求两个集合是否有交集 c语言_高中数学:集合与函数概念知识点总结
  2. mysql datetime转date_一个MySQL时间戳精度引发的血案
  3. html盒子模型子元素怎么水平占满父元素_CSS3——弹性盒模型-flex——父级属性...
  4. eclipse CTRL+F Find/Replace使用正则表达式
  5. 【thymeleaf 】在 thymeleaf 中使用 shiro 标签
  6. matplotlib库绘图基础
  7. rewrite.php wordpress 缓存 固定连接,【转】Wordpress中文标签无法正常连接 - 完美解决方案...
  8. 请简单叙述微型计算机的诞生,2012湖南省计算机等级考试试题 二级C试题考资料...
  9. php的array跟go的array,实现类似php的array_column方法
  10. python画玫瑰图_央视都在用的“南丁格尔玫瑰图”,原来Python也可以画