问答文章1 问答文章501 问答文章1001 问答文章1501 问答文章2001 问答文章2501 问答文章3001 问答文章3501 问答文章4001 问答文章4501 问答文章5001 问答文章5501 问答文章6001 问答文章6501 问答文章7001 问答文章7501 问答文章8001 问答文章8501 问答文章9001 问答文章9501

在SQLServer中为什么不建议使用NotIn子查询_MySQL

发布网友 发布时间:2023-08-10 18:19

我来回答

1个回答

热心网友 时间:2023-08-11 22:11


在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,因此3null就会导致不返回任何行,导致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表的ProctId的定义由Not Null改为Null,此时我们进行一个简单的Not In查询。如图5所示。



图5.Not In的执行计划

在图5中,我们看到一个Row Count Spool操作符,该操作符用于确认ProctId列中是否有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表中的ProctId列定义为允许Null,如果我们将SalesOrderHeader的SalesOrderID列也定义为允许Null时,会发现SQL Server还需要额外的成本确认该列上是否有Null值。如图9所示。



图9.SQL Server通过加入Left Anti Semi Join操作符解决列允许Null的问题

此时Not In对应的等价Not Exist形式变为如代码清单1所示。

SELECT *
FROMSales.SalesOrderHeader a
WHERE NOT EXISTS ( SELECT *
FROM Sales.SalesOrderDetail b
WHERE a.SalesOrderID = b.ProctID )
AND NOT EXISTS ( ( SELECT *
FROM Sales.SalesOrderDetail b
WHEREb.ProctID 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等价形式,将会减少很多麻烦。
声明声明:本网页内容为用户发布,旨在传播知识,不代表本网认同其观点,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。E-MAIL:11247931@qq.com
长沙到西昌。坐火车先从长沙到成都、成都东,再到西昌,哪个方便一些 S先生与P先生谜题的题面 为什么首都设在襄阳 改姓可以不随父母性吗 韩艺瑟怎么改姓? 纸、墨、笔、砚是中国传统的文房四宝,墨的使用最早在 [ ] A.商代后期... 想问下创维光伏E企赢模式有哪些优势,到底值不值得投资啊?有没有合作... 太平洋太享e保百万医疗值得入手吗?每年花多少钱? 爱e满分适合哪些人买?注意哪些问题? 太平洋太享e保百万医疗适合哪些人买?价格多少? 魔兽世界邪恶dk输出 WOW中DK的三板是什么手法。2天一流又是什么呢?现在这版本DK应用什么手法... 魔兽世界DK的两天一流和三板斧手法是什么? 杭州仁和实验的宿舍怎么样啊 杭州仁和实验学校高中伙食怎么样 18k金手镯放在床下怎么会生锈呢?该怎么清洗呀……现在搞得我脑袋大... 红米好为什么不建议吃 杭州好吃饭的地方 就业失业登记证咋办理 辞职后想办就业失业登记证 八方朝向的客厅风水详解,每种方位都有最佳配色 如何看待“内卷”? 绿檀琵琶好还是酸枝琵琶好 soul的人都很污吗? 碧瑠璃的解释 笔记本电脑突然按错一键屏幕文件显示变大软件进不去怎么办 人字梯固定绳子怎么安装 淘宝金主需要多少分 北京众爱慈善商店地址 怎么用qfil刷入rec 这两篇是什么文言文 谢谢 三角函数c等于什么? ...追杀的是一群武士,有一段剧情是男女主在水下,追杀的武士扔 2011年最新韩剧已经更新的,特别好看的有哪些,没出完的也行! ...我都跑去看动漫了,大家有什么好推荐吗?要2011新的韩剧啵 漳州有哪些地方比较好玩的~~~ gta5派奇任务错过了 ...被长大汉语言文学录取 不知道能不能转其他专业,转的几率大吗?_百度... 我大学被调剂到汉语言文学,可我对它兴趣不大,想换专业或者选修其他专 ... ...被调剂到考古学专业,想学英语或者汉语言文学专业,请问转专业容易吗... 山西大同大学汉语言文学怎么样,我是被调剂的,开始没想过会学习这个专业... 被调剂到汉语言文学专业,但是高中语文成绩并不好,我该怎么准备呢?_百 ... 南岸区长江村125号的具体位置在哪儿 什么动物愁思满满? ...腋下温度三十七点三正常么 昨天烧到过三十八度三 女 西葫芦几月份种植 弓箭真的可以射下大雁吗? 古代的弓箭,真的可以射下天上飞的大雁吗? burger和sandwich的区别是什么? 乙酰丙酸保护基脱除原理 今年高考失利,想复读去学艺术类画画,请教些意见,现在还来得及吗? 诚斋集的书籍简介