SQLSERVER语句 in和exists哪个效率高本人测试证明
SQLSERVR语句 in和exists哪个效率高本人测试证明
最近很多人讨论in和exists哪个效率高,今天就自己测试一下
我使用的是客户的数据库GPOSDB(已经有数据)
环境:SQLSERVER2005 Windows7
我的测试条件:两个表作连接根据VC_IC_CardNO字段,查出CT_InhouseCard表中的VC_IC_CardNO(卡号)在CT_FuelingData表中存在的记录
前提:某些人可能在SQL语句中有多个in,或者多个exists,这些情况很难测试效率的,因为大家的条件都不相同
例如下面两个SQL语句
- SELECT OrderNo, SiteCode, AreaCode
- FROM SchedulingProgram
- WHERE AreaCode IN ( 'P', 'M' ) AND SiteCode IN ( SELECT SiteCode
- FROM EnvBasicInfo
- WHERE cityiD = 31 ) AND OrderNo NOT IN (
- SELECT OrderNo
- FROM KK_DeliveryinfoTmp )
上面SQL语句IN里面有IN和NOT IN
- SELECT OrderNo, SiteCode, AreaCode
- FROM SchedulingProgram
- WHERE ( AreaCode IN ( 'P', 'M' ) AND SiteCode IN ( SELECT SiteCode
- FROM EnvBasicInfo
- WHERE cityiD = 31 )
- ) AND NOT EXISTS ( SELECT OrderNo
- FROM KK_DeliveryinfoTmp
- 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表
- USE [GPOSDB]
- GO
- /****** 对象: Table [dbo].[CT_FuelingData] 脚本日期: 08/24/2013 11:00:34 ******/
- SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- SET ANSI_PADDING ON
- GO
- CREATE TABLE [dbo].[CT_FuelingData](
- [RecordNO] [int] IDENTITY(1,1) NOT NULL,
- [I_FD_StationNo] [int] NOT NULL,
- [VC_FD_No] [varchar](50) NOT NULL,
- [VC_FD_Cardno] [varchar](50) NOT NULL,
- [I_FD_CardStatus] [int] NULL,
- [LI_FD_CTC] [bigint] NOT NULL,
- [I_FD_TypeCode] [int] NULL,
- [I_FD_PumpID] [int] NOT NULL,
- [VC_FD_OilType] [varchar](50) NULL,
- [DE_FD_Volume] [decimal](18, 2) NULL,
- [DE_FD_Price] [decimal](18, 2) NULL,
- [DE_FD_Amount] [decimal](18, 2) NULL,
- [I_FD_Point] [decimal](10, 2) NULL,
- [D_FD_DateTime] [datetime] NOT NULL,
- [VC_FD_GroupNo] [varchar](50) NULL,
- [D_FD_GroupDate] [datetime] NULL,
- [DE_FD_CardAmount] [decimal](18, 2) NULL,
- [DE_FD_VolumeTotals] [decimal](18, 2) NULL,
- [DE_FD_AmountTotals] [decimal](18, 2) NULL,
- [I_FD_ISSend] [int] NULL,
- [VC_FD_CardMoneyauthFile] [varchar](50) NULL,
- [D_Month] [datetime] NULL,
- CONSTRAINT [PK_CT_FuelingData_1] PRIMARY KEY CLUSTERED
- (
- [VC_FD_No] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
- SET ANSI_PADDING OFF
CT_InhouseCard表
- USE [GPOSDB]
- GO
- /****** 对象: Table [dbo].[CT_InhouseCard] 脚本日期: 08/24/2013 10:59:58 ******/
- SET ANSI_NULLS ON
- GO
- SET QUOTED_IDENTIFIER ON
- GO
- SET ANSI_PADDING ON
- GO
- CREATE TABLE [dbo].[CT_InhouseCard](
- [RecordNO] [int] IDENTITY(1,1) NOT NULL,
- [VC_IC_CardNO] [varchar](50) NOT NULL,
- [VC_IC_PhysicalNO] [varchar](50) NULL,
- [I_IC_CardType] [int] NULL,
- [VC_IC_UserName] [varchar](50) NULL,
- [VC_IC_JobNO] [varchar](50) NULL,
- [VC_IC_UserID] [varchar](50) NULL,
- [VC_IC_Password] [varchar](50) NULL,
- [DE_IC_CardAmount] [decimal](18, 2) NULL,
- [DE_IC_AppendAmount] [decimal](18, 2) NULL,
- [DE_IC_ConsumerAmount] [decimal](18, 2) NULL,
- [I_IC_ISLost] [int] NULL,
- [D_IC_UsedDateTime] [datetime] NULL,
- [D_IC_UselifeDateTime] [datetime] NULL,
- [I_IC_IssueStationNO] [int] NULL,
- [VC_IC_IssuerNO] [varchar](50) NULL,
- [D_IC_IssueDateTime] [datetime] NULL,
- [D_IC_LastUpdateDateTime] [datetime] NULL,
- [I_IC_CardStatus] [int] NULL,
- [VC_IC_Remark] [varchar](256) NULL,
- CONSTRAINT [PK_CT_InhouseCard] PRIMARY KEY CLUSTERED
- (
- [VC_IC_CardNO] ASC
- )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
- ) ON [PRIMARY]
- GO
- SET ANSI_PADDING OFF
测试脚本
因为这个是客户的数据库,本来里面已经有数据了,所以在测试之前先更新两个表的统计信息,以做到公正
- USE [GPOSDB]
- GO
- UPDATE STATISTICS CT_FuelingData
- UPDATE STATISTICS CT_InhouseCard
- GO
IN语句
- USE [GPOSDB]
- GO
- DBCC DROPCLEANBUFFERS
- GO
- DBCC FREEPROCCACHE
- GO
- SET STATISTICS IO ON
- GO
- SET STATISTICS TIME ON
- GO
- SET STATISTICS PROFILE ON
- GO
- SELECT * FROM [dbo].[CT_FuelingData] WHERE [VC_FD_Cardno] IN (SELECT [VC_IC_CardNO] FROM [dbo].[CT_InhouseCard])
EXISTS语句
- USE [GPOSDB]
- GO
- DBCC DROPCLEANBUFFERS
- GO
- DBCC FREEPROCCACHE
- GO
- SET STATISTICS IO ON
- GO
- SET STATISTICS TIME ON
- GO
- SET STATISTICS PROFILE ON
- GO
- SELECT *
- FROM [dbo].[CT_FuelingData]
- WHERE EXISTS ( SELECT [VC_IC_CardNO]
- FROM [dbo].[CT_InhouseCard]
- WHERE [dbo].[CT_FuelingData].[VC_FD_Cardno] = [dbo].[CT_InhouseCard].[VC_IC_CardNO] )
测试结果
IN语句
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 2 毫秒。
- SQL Server 分析和编译时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 分析和编译时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 分析和编译时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 分析和编译时间:
- CPU 时间 = 31 毫秒,占用时间 = 67 毫秒。
- (167 行受影响)
- 表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- 表 'CT_FuelingData'。扫描计数 1,逻辑读取 31 次,物理读取 1 次,预读 64 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- 表 'CT_InhouseCard'。扫描计数 1,逻辑读取 2 次,物理读取 1 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- (4 行受影响)
- SQL Server 执行时间:
- CPU 时间 = 16 毫秒,占用时间 = 192 毫秒。
EXISTS语句
- SQL Server 分析和编译时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 0 毫秒。
- SQL Server 分析和编译时间:
- CPU 时间 = 0 毫秒,占用时间 = 34 毫秒。
- (167 行受影响)
- 表 'Worktable'。扫描计数 0,逻辑读取 0 次,物理读取 0 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- 表 'CT_FuelingData'。扫描计数 1,逻辑读取 31 次,物理读取 1 次,预读 64 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- 表 'CT_InhouseCard'。扫描计数 1,逻辑读取 2 次,物理读取 1 次,预读 0 次,lob 逻辑读取 0 次,lob 物理读取 0 次,lob 预读 0 次。
- (4 行受影响)
- SQL Server 执行时间:
- CPU 时间 = 0 毫秒,占用时间 = 163 毫秒。
大家可以看到除了执行时间有一点差别,IO是一样的
因为数据量比较大,所以两个查询都用到了Worktable(中间表)来存储中间结果
IN语句的执行计划
EXISTS语句的执行计划
从执行计划可以看到两个SQL语句的开销都是一样的,而且大家都使用了右半连接(Right Semi Join)
至于什么是半连接(Semi-join)大家可以看一下这篇文章:SQL Join的一些总结
总结
从上面实际的执行来比较,,IN语句和EXISTS语句基本上都是一样的效率
如有不对的地方,欢迎大家来拍砖o(∩_∩)o
SQLSERVER语句 in和exists哪个效率高本人测试证明的更多相关文章
- in和exists哪个效率高本人测试证明
in和exists哪个效率高本人测试证明 SQLSERVR语句 in和exists哪个效率高自己测试本人测试证明 最近很多人讨论in和exists哪个效率高,今天就自己测试一下 我使用的是客户的数据库 ...
- 为什么switch...case语句比if...else执行效率高
在C语言中,教科书告诉我们switch...case...语句比if...else if...else执行效率要高,但这到底是为什么呢?本文尝试从汇编的角度予以分析并揭晓其中的奥秘. 第一步,写一个d ...
- 为什么说在使用多条件判断时switch case语句比if语句效率高?
在学习JavaScript中的if控制语句和switch控制语句的时候,提到了使用多条件判断时switch case语句比if语句效率高,但是身为小白的我并没有在代码中看出有什么不同.去度娘找了半个小 ...
- 答:SQLServer DBA 三十问之一: char、varchar、nvarchar之间的区别(包括用途和空间占用);xml类型查找某个节点的数据有哪些方法,哪个效率高;使用存储 过程和使用T-SQL查询数据有啥不一样;
http://www.cnblogs.com/fygh/archive/2011/10/18/2216166.html 1. char.varchar.nvarchar之间的区别(包括用途和空间占用) ...
- 为什么存储过程比sql语句效率高?
存储过程经过预编译处理 而SQL查询没有 SQL语句需要先被数据库引擎处理成低级的指令 然后才执行 -------------------------------------------------- ...
- 关于in与exists的效率讨论
关于in与exists的效率讨论1).select * from A where id in (select id from B)以上查询使用了in语句,in只执行一次,他查出B表的所有id字段并缓存 ...
- SQL点滴35—SQL语句中的exists
原文:SQL点滴35-SQL语句中的exists 比如在Northwind数据库中有一个查询为 SELECT c.CustomerId,CompanyName FROM Customers c WHE ...
- mysql查询语句in和exists二者的区别和性能影响
mysql中的in语句是把外表和内表作hash 连接,而exists语句是对外表作loop循环,每次loop循环再对内表进行查询.一直大家都认为exists比in语句的效率要高,这种说法其实是不准确的 ...
- MySQL IN和EXISTS的效率问题,以及执行优化
网上可以查到很多这样的说法: 如果查询的两个表大小相当,那么用in和exists差别不大.如果两个表中一个较小,一个是大表,则子查询表大的用exists,子查询表小的用in: 例如:表A(小表),表B ...
随机推荐
- ExtJs服务器端代理(Ajax)
服务器端代理: Ajax:在当前域中发送请求 JsonP:跨域的请求 Rest:与服务器进行RESTful(GET/PUT/POST/DELETE)交互 Direct:使用 Ext.direct.M ...
- BestCoder#51
#include <cstdio> #include <iostream> #include <cmath> #include <cstring> us ...
- SOAPUI使用教程-REST请求工作
双击一个REST请求在导航打开的REST请求编辑器窗口: 就像相应的SOAP请求编辑器,这个窗口有以下几部分组成: 工具栏在顶部有标准动作的和端口的下拉菜单轻松修改服务端口 请求编辑器左侧有相应编辑视 ...
- SDOI2009
1226: [SDOI2009]学校食堂Dining Description 小F 的学校在城市的一个偏僻角落,所有学生都只好在学校吃饭.学校有一个食堂,虽然简陋,但食堂大厨总能做出让同学们满意的菜肴 ...
- 洛谷 P1827 美国血统 American Heritage Label:字符串Water
题目描述 农夫约翰非常认真地对待他的奶牛们的血统.然而他不是一个真正优秀的记帐员.他把他的奶牛 们的家谱作成二叉树,并且把二叉树以更线性的“树的中序遍历”和“树的前序遍历”的符号加以记录而 不是用图形 ...
- mac下配置xampp多端口
首先下载并安装完XAMPP软件. 第一步: 打开XAMPP安装目录,找到配置文件. 如:/Applications/XAMPP/etc/httpd.conf 打开后查找 Listen 80 会看到以下 ...
- 纯css来实现提示框
用js用多了,就疏忽了最基本的css了---用title属性来实现提示框.下面言归正传------如何用css实现提示框: 1.利用title属性来实现鼠标滑过某个元素时,实现提示整段内容的功能(利用 ...
- centos7 apache提供文件下载
1 apache安装 # yum -yinstall httpd //安装httpd会自动安装以下的依赖包: apr apr-util httpd-tools mailcap # rpm -qi ht ...
- spring和Hibernate整合
首先导入spring和Hibernate的jar包,以及JDBC和c3p0的jar包, 然后就是Hibernate的XML配置文件,不需要加入映射文件,这里用spring容器管理了. Hibernat ...
- C\C++ 1A2B小游戏源码
学了一段时间,心血来潮写了一个1A2B小游戏,很多人应该玩过,是一个挺有意思的益智小游戏,之前用易语言写过,现在又用C++重写了一下. 编译运行无错,整体程序设计思路为:进入循环,初始化游戏,读入一个 ...