(网页)在SQL Server中为什么不建议使用Not In子查询(转)
转自博客园宋沄剑 英文名:CareySon :
在SQL Server中,子查询可以分为相关子查询和无关子查询,对于无关子查询来说,Not In子句比较常见,但Not In潜在会带来下面两种问题:
- 结果不准确
- 查询性能低下
下面我们来看一下为什么尽量不使用Not In子句。
结果不准确问题
在SQL Server中,Null值并不是一个值,而是表示特定含义,其所表示的含义是“Unknow”,可以理解为未定义或者未知,因此任何与Null值进行比对的二元操作符结果一定为Null,包括Null值本身。而在SQL Server中,Null值的含义转换为Bool类型的结果为False。让我们来看一个简单的例子,如图1所示。

图1.Null值与任何值进行对比结果都为Null
SQL Server提供了“IS”操作符与Null值做对比,用于衡量某个值是否为Null。
那么Not In 的问题在哪呢,如图2所示。

图2.Not In产生不准确的值
在图2中,条件3不属于Not In后面列表的任意一个,该查询却不返回任何值,与预期的结果不同,那么具体原因就是Not In子句对于Null值的处理,在SQL Server中,图2中所示的Not In子句其实可以等价转换为如图3所示的查询。

图3.对于Not In子句来说,可以进行等价转换
在图3中可以看到Not In可以转换为条件对于每个值进行不等比对,并用逻辑与连接起来,而前面提到过Null值与任意其他值做比较时,结果永远为Null,在Where条件中也就是False,因此3<>null就会导致不返回任何行,导致Not In子句产生的结果在意料之外。
因此,Not In子句如果来自于某个表或者列表很长,其中大量值中即使存在一个Null值,也会导致最终结果不会返回任何数据。
解决办法?
解决办法就是不使用Not In,而使用Not Exists作为替代。Exists的操作符不会返回Null,只会根据子查询中的每一行决定返回True或者False,当遇到Null值时,只会返回False,而不会由某个Null值导致整个子查询表达式为Null。对于图2中所示的查询,我们可以改写为子查询,如图4所示。

图4.Not Exists可以正确返回结果
Not In导致的查询性能低下
前面我们可以看出,Not In的主要问题是由于对Null值的处理问题所导致,那么对Null值的处理究竟为什么会导致性能问题?让我们来看图5的示例。图5中,我们使用了Adventurework示例数据库,并为了演示目的将SalesOrderDetail表的ProductId的定义由Not Null改为Null,此时我们进行一个简单的Not In查询。如图5所示。

图5.Not In的执行计划
在图5中,我们看到一个Row Count Spool操作符,该操作符用于确认ProductId列中是否有Null值(过程是对比总行数和非Null行数,不想等则为有Null值,虽然我们知道该列中没有Null值,但由于列定义是允许Null的,因此SQL Server必须进行额外的确认),而该操作符占用了接近一半的查询成本。因此我们对比Not Exists,如图6所示。

图6.Not In Vs Not Exists
由图6可以看出,Not In的执行成本几乎是Not Exists的3倍,仅仅是由于SQL Server需要确认允许Null列中是否存在Null。根据图3中Not In的等价形式,我们完全可以将Not In转换为等价的Not Exist形式,如图7所示。

图7.Not In转换为Not Exists
我们来对比图7和其等价Not In查询的成本,如图8所示。

图8.成本上完全等价
因此我们可以看到Not In需要额外的步骤处理Null值,上述情况是仅仅在SalesOrderDetail表中的ProductId列定义为允许Null,如果我们将SalesOrderHeader的SalesOrderID列也定义为允许Null时,会发现SQL Server还需要额外的成本确认该列上是否有Null值。如图9所示。

图9.SQL Server通过加入Left Anti Semi Join操作符解决列允许Null的问题
此时Not In对应的等价Not Exist形式变为如代码清单1所示。
SELECT *
FROM Sales.SalesOrderHeader a
WHERE NOT EXISTS ( SELECT *
FROM Sales.SalesOrderDetail b
WHERE a.SalesOrderID = b.ProductID )
AND NOT EXISTS ( ( SELECT *
FROM Sales.SalesOrderDetail b
WHERE b.ProductID IS NULL
) )
AND NOT EXISTS ( SELECT 1
FROM ( SELECT *
FROM Sales.SalesOrderHeader
) AS c
WHERE c.SalesOrderID IS NULL )
代码清单1.当连接列两列定义都允许Null时,Not In等价的Not Exists形式
此时我们简单对比Not In和Not Exists的IO情况,如图10所示。

图10.Not In吃掉很高的IO
本文阐述了Not In 的实现原理以及所带来的数据不一致和性能问题,在写查询时,尽量避免使用Not In,而转换为本文提供的Not Exists等价形式,将会减少很多麻烦。
原文:http://www.cnblogs.com/CareySon/p/4955123.html
(网页)在SQL Server中为什么不建议使用Not In子查询(转)的更多相关文章
- 在SQL Server中为什么不建议使用Not In子查询
在SQL Server中,子查询可以分为相关子查询和无关子查询,对于无关子查询来说,Not In子句比较常见,但Not In潜在会带来下面两种问题: 结果不准确 查询性能低下 下面 ...
- SQL SERVER 中 实现主表1行记录,子表多行记录 整合成一条虚拟列
表中有这样的记录,简单的主子表,现要想通过left join 语句把两表关联起来 select * from tbl_diary_reback a left join tbl_diary_reback ...
- 《SQL Server 2012 T-SQL基础》读书笔记 - 4.子查询
Chapter 4 Subqueries 子查询分为:独立子查询(Self-Contained Subqueries)和相关子查询(Correlated Subqueries),独立子查询可以单独拿出 ...
- SQL Server中INNER JOIN与子查询IN的性能测试
这个月碰到几个人问我关于"SQL SERVER中INNER JOIN 与 IN两种写法的性能孰优孰劣?"这个问题.其实这个概括起来就是SQL Server中INNER JOIN与子 ...
- SQL Server中查询数据库及表的信息语句
/* -- 本文件主要是汇总了 Microsoft SQL Server 中有关数据库与表的相关信息查询语句. -- 下面的查询语句中一般给出两种查询方法, -- A方法访问系统表,适应于SQL 20 ...
- 多个程序对sql server中的表进行查询和插入操作导致死锁
最近在做一个项目,是要用多个程序对sql server中的相同的数据库进行操作(查询和插入),所以在开始的时候常会出现死锁问题,后来在网上进行了咨询,发现了一些解决方法,留作大家参考: 并发去操纵一张 ...
- SQL Server中的“最大并行度”的配置建议
SQL Server中的最大并行度(max degree of parallelism)如何设置呢? 设置max degree of parallelism有什么好的建议和指导方针呢?在微软官方文档R ...
- 在SQL Server中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么?
在SQL Server 在SQL Server中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么? 中,为何都建议禁止 VIA 协议,VIA协议具体内容是什么? 在SQL Server中,为何 ...
- SQL Server中的高可用性(2)----文件与文件组
在谈到SQL Server的高可用性之前,我们首先要谈一谈单实例的高可用性.在单实例的高可用性中,不可忽略的就是文件和文件组的高可用性.SQL Server允许在某些文件损坏或离线的情况下,允 ...
随机推荐
- 内存管理cpuset,mempolicy[原理]
介绍cpuset,mbind,set_mempolicy在内存管理上的应用 change log :确定先从mempolicy的man 手册翻译开始研究,计划如下 .先从man手册入手,通过实现mem ...
- python 特定份数的数据概率统计(原创)
使用numpy模块中的histogram函数模块 Histogram(a,bins=10,range=None,normed=False,weights=None)其中, a是保存待统计数据的数组, ...
- 关于微信JS SDK接口wx.previewImage预览接口的使用
然后后之前的项目,突然往微信上迁移了,一些微信的接口没怎么用过,比较陌生,这次的功能是想调用微信的接口,实现图片放大的功能, 就找到官方文档:http://qydev.weixin.qq.com/wi ...
- HTTPS到底是个什么鬼?
HTTPS随处可见,那么它到底是个什么鬼?本文我们一起来探讨一下HTTPS为什么是安全的,以及HTTPS连接建立的过程. 一.HTTPS为什么是安全的? HTTP使用明文通信,可能会被第三方窃听.篡改 ...
- OkHttp3 任务队列
OkHttp3 有两种运行方式: 1.同步阻塞调用并且直接返回: 2.通过内部线程池分发调度实现非阻塞的异步回调; 下面讲的是非阻塞异步回调,OkHttp在多并发网络下的分发调度过程,主要是Dispa ...
- 读书笔记(06) - 语法基础 - JavaScript高级程序设计
写在开头 本篇是小红书笔记的第六篇,也许你会奇怪第六篇笔记才写语法基础,笔者是不是穿越了. 答案当然是没有,笔者在此分享自己的阅读心得,不少人翻书都是从头开始,结果永远就只在前几章. 对此,笔者换了随 ...
- 【随笔】nginx add_header指令的使用
nginx配置文件通过使用add_header指令来设置response header. 具体方法如下: add_header key value add_header Cache-Control n ...
- JVM内存区域划分及垃圾回收
第一部分.闲扯+概述 近来在研读<深入理解java虚拟机>一书,读完之后做个小结,算是记录一下自己的学习所得,在成长的路上,只能死磕. 要理解JVM,就要先从其内存区域划分开始,知道其由几 ...
- java实现把对象数组通过excel方式导出的功能
一.导入相关jar包,pom依赖如下: <dependency> <groupId>org.apache.poi</groupId> <artifactId& ...
- zookeeper ZAB协议 Follower和leader源码分析
Follower处理逻辑 void followLeader() throws InterruptedException { //... try { //获取leader server QuorumS ...