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

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

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

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

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

  2. mysql中or和in,in和exists的效率问题

     mysql中or和in的效率问题      在网上一直看到的是or和in的效率没啥区别,一直也感觉是这样,前几天刚好在看<mysql数据库开发的36条军规>的文章,里面提到了or和in的 ...

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

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

  4. C# 多线程 Parallel.For 和 For 谁的效率高?那么 Parallel.ForEach 和 ForEach 呢?

    还是那句话:十年河东,十年河西,莫欺少年穷. 今天和大家探讨一个问题:Parallel.For 和 For 谁的效率高呢? 从CPU使用方面而言,Parallel.For 属于多线程范畴,可以开辟多个 ...

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

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

  6. IN和EXISTS、not in 和not exists的效率详解

    从效率来看: 1) select * from T1 where exists(select 1 from T2 where T1.a=T2.a) ; T1数据量小而T2数据量非常大时,T1<& ...

  7. BZOJ 最大公约数 (通俗易懂&效率高&欧拉函数)

    题目 题目描述 给定整数\(N\),求\(1 \le x,y \le N\)且\(gcd(x,y)\)为素数的数对\((x,y)\)有多少对. \(gcd(x,y)\)即求\(x,y\)的最大公约数. ...

  8. Dubbo入门到精通学习笔记(十五):Redis集群的安装(Redis3+CentOS)、Redis集群的高可用测试(含Jedis客户端的使用)、Redis集群的扩展测试

    文章目录 Redis集群的安装(Redis3+CentOS) 参考文档 Redis 集群介绍.特性.规范等(可看提供的参考文档+视频解说) Redis 集群的安装(Redis3.0.3 + CentO ...

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

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

随机推荐

  1. Jenkins + robot framework自动发送邮件报告

    一.Jenkins安装插件 进入系统管理—插件管理—可选插件下安装以下插件Email-ext plugin.Email-ext Template Plugin. 安装完如下: 二.系统设置 1.设置系 ...

  2. 【云图】如何制作全国KTV查询系统?

    原文:[云图]如何制作全国KTV查询系统? 摘要:本文以[唱吧]531麦霸音乐节为案例,详细解读了如何导入自有数据到高德云图,并进行检索和展示.最后,调起高德mobile地图来进行路线规划和周边查询. ...

  3. Cookie基础

    周末百度笔试,答得题都会,就是不仔细不心细,提前一个小时交卷子,想起来就已经晚了.问了一个cookie的问题,我SB的蒙住了,于是乎,似乎是跪掉了,回来后总结了下Cooke的相关问题.###获取coo ...

  4. 2013级C++第13周(春)项目——继承的进一步话题与GUI应用开发

    课程首页在:http://blog.csdn.net/sxhelijian/article/details/11890759,内有完整教学方案及资源链接 第一部分 程序阅读:阅读以下类的定义,请说出在 ...

  5. windows7股票的,win8残疾人,安装Han澳大利亚sinoxn个时间,sinox它支持大多数windows软体

    腾讯科技: 正如先前所宣布,微软,10一个月31迄今,Windows 7家庭基础版.家庭高级版和旗舰版盒装版本将不再销售.而微软是不会再OEM制造商授予许可数量的三个版本. windows7股票的.由 ...

  6. $.each()方法详解

    $.each()方法详解 each()函数具有十分强大的遍历功能,可以遍历一维数组.多维数组.Dom.Json等. 在JavaScript中使用$.each可以大大减轻我们的工作量. 1.处理一维数组 ...

  7. iOS MapKit导航及地理转码辅助类

    头文件: #import <Foundation/Foundation.h> #import <MapKit/MapKit.h> @interface DirectionRou ...

  8. EasyUI的后台界面

    EasyUI的后台界面搭建及极致重构 〇.前言 要了解一个东西长什么样,至少得让我们能看到,才能提出针对性的见解.所以,为了言之有物,而不是凭空漫谈,我们先从UI说起,后台管理页面的UI我们将使用应用 ...

  9. LibVLC audio controls

    原文 http://www.videolan.org/developers/vlc/doc/doxygen/html/group__libvlc__audio.html LibVLC audio co ...

  10. lua及luci学习

    由于项目需要对Luci进行修改,所以这里开始地luci进行较深入的研究. 探索其中的运行路径. Openwrt默认的HTTP服务器为uhttpd,该WEB服务器是由Luci的开发者自行开发的,非常小巧 ...