SQLSERVER语句 in和exists哪个效率高本人测试证明
2013-08-24 11:52
344 查看
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语句基本上都是一样的效率
[b]如有不对的地方,欢迎大家来拍砖o(∩_∩)o [/b]
相关文章推荐
- in和exists哪个效率高本人测试证明
- SqlServer中in和exists的区别效率问题
- SQLServer语句执行效率及性能测试
- SqlServer中in和exists的区别效率问题
- Sqlserver 测试语句效率的几项设置语句
- sql语句in和exists的效率
- ORACLE in与exists语句的查询效率的区别
- 在sql语句多表连接中,in、exists、join那个效率更高一点
- SQLServer语句执行效率及性能测试
- SqlServer点滴:in和exists的效率问题
- SQL优化--Exists和in的效率哪个高
- SQL优化--Exists和in的效率哪个高
- 大唐笔试题 oracle中,if exists 和 in 哪个效率更高
- SQL优化--Exists和in的效率哪个高
- oracle中的exists 和not exists 用法 in与exists语句的效率问题
- Linq to SQL语句之 Group By /Having和Exists/In/AnyAll/Contains
- NOT EXISTS替代NOT IN EXISTS替换DISTINCT 识别‘低效执行’的SQL语句
- 如何测试sql语句性能,提高执行效率(装载)
- SQL语句执行效率及性能测试
- LINQ体验(7)——LINQ to SQL语句之Group By/Having和Exists/In/Any/All/Contains