SQLSERVR语句 in和exists哪个效率高本人测试证明

最近很多人讨论in和exists哪个效率高,今天就自己测试一下

我使用的是客户的数据库GPOSDB(已经有数据)

环境:SQLSERVER2005   Windows7

我的测试条件:两个表作连接根据VC_IC_CardNO字段,查出CT_InhouseCard表中的VC_IC_CardNO(卡号)在CT_FuelingData表中存在的记录

前提:某些人可能在SQL语句中有多个in,或者多个exists,这些情况很难测试效率的,因为大家的条件都不相同

例如下面两个SQL语句

  1. SELECT OrderNo, SiteCode, AreaCode
  2. FROM SchedulingProgram
  3. WHERE AreaCode IN ( 'P', 'M' ) AND SiteCode IN ( SELECT SiteCode
  4. FROM EnvBasicInfo
  5. WHERE cityiD = 31 ) AND OrderNo NOT IN (
  6. SELECT OrderNo
  7. FROM KK_DeliveryinfoTmp )

上面SQL语句IN里面有IN和NOT IN

  1. SELECT OrderNo, SiteCode, AreaCode
  2. FROM SchedulingProgram
  3. WHERE ( AreaCode IN ( 'P', 'M' ) AND SiteCode IN ( SELECT SiteCode
  4. FROM EnvBasicInfo
  5. WHERE cityiD = 31 )
  6. ) AND NOT EXISTS ( SELECT OrderNo
  7. FROM KK_DeliveryinfoTmp
  8. WHERE KK_DeliveryinfoTmp.OrderNo = SchedulingProgram.OrderNo )

上面的SQL语句IN里面又有NOT EXISTS

这样的情况很难测试同等条件下IN语句和EXISTS语句的效率

还有一个非SARG运算符

在《SQLSERVER企业级平台管理实践》的第424页里提到:

SQLSERVER对筛选条件(search argument/SARG)的写法有一定的建议

对于不使用SARG运算符的表达式,索引是没有用的,SQLSERVER对它们很难使用比较优化的做法。非SARG运算符包括

NOT、<>、NOT EXISTS、NOT IN、NOT LIKE和内部函数,例如:Convert、Upper等

所以当您的表中有索引并且SQL语句包含非SARG运算符,那么当测试SQL语句的执行时间的时候肯定相差很大,

因为有些SQL语句走索引,有些SQL语句不走索引


建表脚本

注意:两个表中都有索引!!

CT_FuelingData表

  1. USE [GPOSDB]
  2. GO
  3. /****** 对象: Table [dbo].[CT_FuelingData] 脚本日期: 08/24/2013 11:00:34 ******/
  4. SET ANSI_NULLS ON
  5. GO
  6. SET QUOTED_IDENTIFIER ON
  7. GO
  8. SET ANSI_PADDING ON
  9. GO
  10. CREATE TABLE [dbo].[CT_FuelingData](
  11. [RecordNO] [int] IDENTITY(1,1) NOT NULL,
  12. [I_FD_StationNo] [int] NOT NULL,
  13. [VC_FD_No] [varchar](50) NOT NULL,
  14. [VC_FD_Cardno] [varchar](50) NOT NULL,
  15. [I_FD_CardStatus] [int] NULL,
  16. [LI_FD_CTC] [bigint] NOT NULL,
  17. [I_FD_TypeCode] [int] NULL,
  18. [I_FD_PumpID] [int] NOT NULL,
  19. [VC_FD_OilType] [varchar](50) NULL,
  20. [DE_FD_Volume] [decimal](18, 2) NULL,
  21. [DE_FD_Price] [decimal](18, 2) NULL,
  22. [DE_FD_Amount] [decimal](18, 2) NULL,
  23. [I_FD_Point] [decimal](10, 2) NULL,
  24. [D_FD_DateTime] [datetime] NOT NULL,
  25. [VC_FD_GroupNo] [varchar](50) NULL,
  26. [D_FD_GroupDate] [datetime] NULL,
  27. [DE_FD_CardAmount] [decimal](18, 2) NULL,
  28. [DE_FD_VolumeTotals] [decimal](18, 2) NULL,
  29. [DE_FD_AmountTotals] [decimal](18, 2) NULL,
  30. [I_FD_ISSend] [int] NULL,
  31. [VC_FD_CardMoneyauthFile] [varchar](50) NULL,
  32. [D_Month] [datetime] NULL,
  33. CONSTRAINT [PK_CT_FuelingData_1] PRIMARY KEY CLUSTERED
  34. (
  35. [VC_FD_No] ASC
  36. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  37. ) ON [PRIMARY]
  38.  
  39. GO
  40. SET ANSI_PADDING OFF

CT_InhouseCard表

  1. USE [GPOSDB]
  2. GO
  3. /****** 对象: Table [dbo].[CT_InhouseCard] 脚本日期: 08/24/2013 10:59:58 ******/
  4. SET ANSI_NULLS ON
  5. GO
  6. SET QUOTED_IDENTIFIER ON
  7. GO
  8. SET ANSI_PADDING ON
  9. GO
  10. CREATE TABLE [dbo].[CT_InhouseCard](
  11. [RecordNO] [int] IDENTITY(1,1) NOT NULL,
  12. [VC_IC_CardNO] [varchar](50) NOT NULL,
  13. [VC_IC_PhysicalNO] [varchar](50) NULL,
  14. [I_IC_CardType] [int] NULL,
  15. [VC_IC_UserName] [varchar](50) NULL,
  16. [VC_IC_JobNO] [varchar](50) NULL,
  17. [VC_IC_UserID] [varchar](50) NULL,
  18. [VC_IC_Password] [varchar](50) NULL,
  19. [DE_IC_CardAmount] [decimal](18, 2) NULL,
  20. [DE_IC_AppendAmount] [decimal](18, 2) NULL,
  21. [DE_IC_ConsumerAmount] [decimal](18, 2) NULL,
  22. [I_IC_ISLost] [int] NULL,
  23. [D_IC_UsedDateTime] [datetime] NULL,
  24. [D_IC_UselifeDateTime] [datetime] NULL,
  25. [I_IC_IssueStationNO] [int] NULL,
  26. [VC_IC_IssuerNO] [varchar](50) NULL,
  27. [D_IC_IssueDateTime] [datetime] NULL,
  28. [D_IC_LastUpdateDateTime] [datetime] NULL,
  29. [I_IC_CardStatus] [int] NULL,
  30. [VC_IC_Remark] [varchar](256) NULL,
  31. CONSTRAINT [PK_CT_InhouseCard] PRIMARY KEY CLUSTERED
  32. (
  33. [VC_IC_CardNO] ASC
  34. )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
  35. ) ON [PRIMARY]
  36.  
  37. GO
  38. SET ANSI_PADDING OFF

测试脚本

因为这个是客户的数据库,本来里面已经有数据了,所以在测试之前先更新两个表的统计信息,以做到公正

  1. USE [GPOSDB]
  2. GO
  3. UPDATE STATISTICS CT_FuelingData
  4. UPDATE STATISTICS CT_InhouseCard
  5. GO

IN语句

  1. USE [GPOSDB]
  2. GO
  3. DBCC DROPCLEANBUFFERS
  4. GO
  5. DBCC FREEPROCCACHE
  6. GO
  7. SET STATISTICS IO ON
  8. GO
  9. SET STATISTICS TIME ON
  10. GO
  11. SET STATISTICS PROFILE ON
  12. GO
  13. SELECT * FROM [dbo].[CT_FuelingData] WHERE [VC_FD_Cardno] IN (SELECT [VC_IC_CardNO] FROM [dbo].[CT_InhouseCard])

EXISTS语句

  1. USE [GPOSDB]
  2. GO
  3. DBCC DROPCLEANBUFFERS
  4. GO
  5. DBCC FREEPROCCACHE
  6. GO
  7. SET STATISTICS IO ON
  8. GO
  9. SET STATISTICS TIME ON
  10. GO
  11. SET STATISTICS PROFILE ON
  12. GO
  13. SELECT *
  14. FROM [dbo].[CT_FuelingData]
  15. WHERE EXISTS ( SELECT [VC_IC_CardNO]
  16. FROM [dbo].[CT_InhouseCard]
  17. WHERE [dbo].[CT_FuelingData].[VC_FD_Cardno] = [dbo].[CT_InhouseCard].[VC_IC_CardNO] )

测试结果

IN语句

  1. SQL Server 执行时间:
  2. CPU 时间 = 0 毫秒,占用时间 = 2 毫秒。
  3. SQL Server 分析和编译时间:
  4. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  5.  
  6. SQL Server 执行时间:
  7. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  8. SQL Server 分析和编译时间:
  9. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  10.  
  11. SQL Server 执行时间:
  12. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  13. SQL Server 分析和编译时间:
  14. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  15.  
  16. SQL Server 执行时间:
  17. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  18. SQL Server 分析和编译时间:
  19. CPU 时间 = 31 毫秒,占用时间 = 67 毫秒。
  20.  
  21. (167 行受影响)
  22. 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  23. 'CT_FuelingData'。扫描计数 1,逻辑读取 31 次,物理读取 1 次,预读 64 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  24. 'CT_InhouseCard'。扫描计数 1,逻辑读取 2 次,物理读取 1 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  25.  
  26. (4 行受影响)
  27.  
  28. SQL Server 执行时间:
  29. CPU 时间 = 16 毫秒,占用时间 = 192 毫秒。

EXISTS语句

  1. SQL Server 分析和编译时间:
  2. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  3.  
  4. SQL Server 执行时间:
  5. CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
  6. SQL Server 分析和编译时间:
  7. CPU 时间 = 0 毫秒,占用时间 = 34 毫秒。
  8.  
  9. (167 行受影响)
  10. 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  11. 'CT_FuelingData'。扫描计数 1,逻辑读取 31 次,物理读取 1 次,预读 64 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  12. 'CT_InhouseCard'。扫描计数 1,逻辑读取 2 次,物理读取 1 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
  13.  
  14. (4 行受影响)
  15.  
  16. SQL Server 执行时间:
  17. CPU 时间 = 0 毫秒,占用时间 = 163 毫秒。

大家可以看到除了执行时间有一点差别,IO是一样的

因为数据量比较大,所以两个查询都用到了Worktable(中间表)来存储中间结果

IN语句的执行计划

EXISTS语句的执行计划

从执行计划可以看到两个SQL语句的开销都是一样的,而且大家都使用了右半连接(Right Semi Join)

至于什么是半连接(Semi-join)大家可以看一下这篇文章:SQL Join的一些总结

总结

从上面实际的执行来比较,,IN语句和EXISTS语句基本上都是一样的效率

如有不对的地方,欢迎大家来拍砖o(∩_∩)o

SQLSERVER语句 in和exists哪个效率高本人测试证明的更多相关文章

  1. in和exists哪个效率高本人测试证明

    in和exists哪个效率高本人测试证明 SQLSERVR语句 in和exists哪个效率高自己测试本人测试证明 最近很多人讨论in和exists哪个效率高,今天就自己测试一下 我使用的是客户的数据库 ...

  2. 为什么switch...case语句比if...else执行效率高

    在C语言中,教科书告诉我们switch...case...语句比if...else if...else执行效率要高,但这到底是为什么呢?本文尝试从汇编的角度予以分析并揭晓其中的奥秘. 第一步,写一个d ...

  3. 为什么说在使用多条件判断时switch case语句比if语句效率高?

    在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...

  4. 答:SQLServer DBA 三十问之一: char、varchar、nvarchar之间的区别(包括用途和空间占用);xml类型查找某个节点的数据有哪些方法,哪个效率高;使用存储 过程和使用T-SQL查询数据有啥不一样;

    http://www.cnblogs.com/fygh/archive/2011/10/18/2216166.html 1. char.varchar.nvarchar之间的区别(包括用途和空间占用) ...

  5. 为什么存储过程比sql语句效率高?

    存储过程经过预编译处理 而SQL查询没有 SQL语句需要先被数据库引擎处理成低级的指令 然后才执行 -------------------------------------------------- ...

  6. 关于in与exists的效率讨论

    关于in与exists的效率讨论1).select * from A where id in (select id from B)以上查询使用了in语句,in只执行一次,他查出B表的所有id字段并缓存 ...

  7. SQL点滴35—SQL语句中的exists

    原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHE ...

  8. mysql查询语句in和exists二者的区别和性能影响

    mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询.一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的 ...

  9. MySQL IN和EXISTS的效率问题,以及执行优化

    网上可以查到很多这样的说法: 如果查询的两个表大小相当,那么用in和exists差别不大.如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: 例如:表A(小表),表B ...

随机推荐

  1. ExtJs服务器端代理(Ajax)

    服务器端代理: Ajax:在当前域中发送请求 JsonP:跨域的请求 Rest:与服务器进行RESTful(GET/PUT/POST/DELETE)交互 Direct:使用  Ext.direct.M ...

  2. BestCoder#51

    #include <cstdio> #include <iostream> #include <cmath> #include <cstring> us ...

  3. SOAPUI使用教程-REST请求工作

    双击一个REST请求在导航打开的REST请求编辑器窗口: 就像相应的SOAP请求编辑器,这个窗口有以下几部分组成: 工具栏在顶部有标准动作的和端口的下拉菜单轻松修改服务端口 请求编辑器左侧有相应编辑视 ...

  4. SDOI2009

    1226: [SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴 ...

  5. 洛谷 P1827 美国血统 American Heritage Label:字符串Water

    题目描述 农夫约翰非常认真地对待他的奶牛们的血统.然而他不是一个真正优秀的记帐员.他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形 ...

  6. mac下配置xampp多端口

    首先下载并安装完XAMPP软件. 第一步: 打开XAMPP安装目录,找到配置文件. 如:/Applications/XAMPP/etc/httpd.conf 打开后查找 Listen 80 会看到以下 ...

  7. 纯css来实现提示框

    用js用多了,就疏忽了最基本的css了---用title属性来实现提示框.下面言归正传------如何用css实现提示框: 1.利用title属性来实现鼠标滑过某个元素时,实现提示整段内容的功能(利用 ...

  8. centos7 apache提供文件下载

    1 apache安装 # yum -yinstall httpd //安装httpd会自动安装以下的依赖包: apr apr-util httpd-tools mailcap # rpm -qi ht ...

  9. spring和Hibernate整合

    首先导入spring和Hibernate的jar包,以及JDBC和c3p0的jar包, 然后就是Hibernate的XML配置文件,不需要加入映射文件,这里用spring容器管理了. Hibernat ...

  10. C\C++ 1A2B小游戏源码

    学了一段时间,心血来潮写了一个1A2B小游戏,很多人应该玩过,是一个挺有意思的益智小游戏,之前用易语言写过,现在又用C++重写了一下. 编译运行无错,整体程序设计思路为:进入循环,初始化游戏,读入一个 ...