每当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

贪图1.Null值与其他价值进行自查自纠结果还也Null

    SQL Server提供了“IS”操作符与Null值做对比,用于衡量某个值是否也Null。

 

    那么Not In 的题材在啊吧,如图2所展示。

图片 2   

贪图2.Not In发出不确切之价值

 

     在祈求2面临,条件3请勿属Not
In后面列表的人身自由一个,该查询也不回去外价值,与预期的结果不同,那么具体由就Not
In子句对于Null值的处理,在SQL Server中,图2受所显示之Not
In子句实在可以等转换为使图3所著之询问。

图片 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

图4.Not Exists可以正确返回结果

 

Not In导致的询问性能低下

    前面我们可看,Not
In的要紧问题是出于对Null值的处理问题所导致,那么对Null值的处理究竟为何会促成性问题?让咱们来拘禁图5的演示。图5饱受,我们运用了Adventurework示例数据库,并为演示目的将SalesOrderDetail表的ProductId的概念由Not
Null改吧Null,此时我们进行一个大概的Not In查询。如图5所显示。

图片 5

祈求5.Not In的推行计划

 

    在觊觎5遭,我们视一个Row Count
Spool操作符,该操作符用于确认ProductId列中是否来Null值(过程是比照总行多次与非Null行数,不思量当则也出Null值,虽然咱知晓该列中没Null值,但由列定义是容Null的,因此SQL
Server必须开展额外的认可),而该操作符占用了仿佛一半的询问资金。因此我们相比Not
Exists,如图6所出示。

图片 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

图7.Not In转换为Not Exists

    我们来对比图7和那等价Not In查询的成本,如图8所出示。

图片 8

祈求8.成本上完全等价

 

    因此我们得以视Not
In需要分外的步骤处理Null值,上述情况是单纯以SalesOrderDetail表中之ProductId列定义也允许Null,如果我们拿SalesOrderHeader的SalesOrderID列也定义也允许Null时,会发现SQL
Server还需要额外的本确认该列上是否来Null值。如图9所著。

图片 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

希冀10.Not In吃少那个高的IO

正文阐述了Not In
的兑现原理与所带来的数目不一样和性能问题,在形容查询时,尽量避免使用Not
In,而转换为本文提供的Not Exists等价格式,将会回落过多难为。

原文:http://www.cnblogs.com/CareySon/p/4955123.html

相关文章