私は常にデフォルトにしていますNOT EXISTS。
実行計画は現時点では同じかもしれませんが、いずれかの列がNULLs を許可するように将来変更された場合、NOT INバージョンはより多くの作業を行う必要があります (NULLデータに s が実際に存在しない場合でも) およびNOT INif NULLsが存在する場合のセマンティクスとにかくあなたが望むものになる可能性は低いです。
どちらProducts.ProductIDも[Order Details].ProductID許可NULLしない場合NOT INは、次のクエリと同じように扱われます。
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
正確な計画は異なる場合がありますが、私の例のデータでは次のようになります。

かなり一般的な誤解は、相関サブクエリは結合と比較して常に「悪い」ということです。ネストされたループ プラン (行ごとに評価されるサブクエリ) を強制する場合は確かにそうなる可能性がありますが、このプランにはアンチ セミ ジョイン論理演算子が含まれています。アンチセミ結合はネストされたループに限定されませんが、ハッシュまたはマージ (この例のように) 結合も使用できます。
/*Not valid syntax but better reflects the plan*/
SELECT p.ProductID,
p.ProductName
FROM Products p
LEFT ANTI SEMI JOIN [Order Details] od
ON p.ProductId = od.ProductId
可能な場合、クエリは次のようになり[Order Details].ProductIDますNULL
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
この理由は、 s が[Order Details]含まれている場合の正しいセマンティクスNULL ProductIdは、結果を返さないことです。プランに追加されたこれを確認するには、追加のアンチ セミ ジョインと行カウント スプールを参照してください。

Products.ProductIDも可能になるように変更された場合NULL、クエリは次のようになります
SELECT ProductID,
ProductName
FROM Products p
WHERE NOT EXISTS (SELECT *
FROM [Order Details] od
WHERE p.ProductId = od.ProductId)
AND NOT EXISTS (SELECT *
FROM [Order Details]
WHERE ProductId IS NULL)
AND NOT EXISTS (SELECT *
FROM (SELECT TOP 1 *
FROM [Order Details]) S
WHERE p.ProductID IS NULL)
その理由は、サブクエリがまったく結果を返さない場合 (つまり、テーブルが空である場合)を除いNULL Products.ProductIdて、結果に a を返すべきではないためです。その場合はそうすべきです。私のサンプルデータの計画では、これは以下のように別のアンチセミ結合を追加することで実装されています。NOT IN[Order Details]

この効果は、Buckley によって既にリンクされているブログ投稿に示されています。この例では、論理読み取りの数が約 400 から 500,000 に増加しています。
さらに、シングルNULLは行数をゼロに減らすことができるという事実により、カーディナリティの推定が非常に困難になります。SQL Server がこれが発生すると想定しているが、実際にはデータに行がなかった場合、これがより大きなクエリの一部に過ぎず、不適切なネストされたループが高価なサブルーチンの繰り返し実行を引き起こしてNULLいる場合、残りの実行プランは壊滅的に悪化する可能性がありますたとえば、ツリー。
NOT INただし、 on a NULL-able 列の実行計画はこれだけではありません。この記事では、データベースに対するクエリの別の記事を示しAdventureWorks2008ます。
列の場合、またはnull可能またはnull不可の列の場合、次の計画が得られますNOT IN。NOT NULLNOT EXISTS

列がNULL-able に変わると、NOT INプランは次のようになります

追加の内部結合演算子をプランに追加します。ここ でこの 装置について 説明 し ます. 前の単一の相関インデックス シークを、Sales.SalesOrderDetail.ProductID = <correlated_product_id>外側の行ごとに 2 つのシークに変換するだけです。追加のものはオンWHERE Sales.SalesOrderDetail.ProductID IS NULLです。
これはアンチセミ結合の下にあるため、行が返された場合、2 番目のシークは発生しません。ただし、 sSales.SalesOrderDetailが含まれていない場合はNULL ProductID、必要なシーク操作の数が 2 倍になります。