日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > 数据库 >内容正文

数据库

在SQL Server中为什么不建议使用Not In子查询

發布時間:2025/3/8 数据库 14 豆豆
生活随笔 收集整理的這篇文章主要介紹了 在SQL Server中为什么不建议使用Not In子查询 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
原文:在SQL Server中為什么不建議使用Not In子查詢

??? 在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等價形式,將會減少很多麻煩。

總結

以上是生活随笔為你收集整理的在SQL Server中为什么不建议使用Not In子查询的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。