[解決済み] NOT IN vs NOT EXISTS
質問
これらのクエリのうち、どちらが速いか?
NOT EXISTSです。
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE NOT EXISTS (
SELECT 1
FROM Northwind..[Order Details] od
WHERE p.ProductId = od.ProductId)
またはNOT IN。
SELECT ProductID, ProductName
FROM Northwind..Products p
WHERE p.ProductID NOT IN (
SELECT ProductID
FROM Northwind..[Order Details])
クエリ実行計画では、どちらも同じことをすると言っています。 もしそうであれば、どちらが推奨される形なのでしょうか?
これはNorthWindのデータベースを元にしたものです。
[編集]をクリックします。
ちょうどこの役に立つ記事を見つけました。 http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
NOT EXISTSで我慢しようかな。
どのように解決するのですか?
私はいつもデフォルトで
NOT EXISTS
.
現時点では実行計画は同じかもしれませんが、将来どちらかのカラムが変更され
NULL
となります。
NOT IN
のバージョンでは、より多くの作業を行う必要があります(たとえ
NULL
のセマンティックは、実際にデータ中に存在するものではありません。
NOT IN
もし
NULL
s
は
は、いずれにせよ、あなたが望むものである可能性は低いでしょう。
どちらも
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)
この理由は、正しいセマンティクスが
[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)
その1つの理由は
NULL
Products.ProductId
は結果で返されるべきではありません。
ただし
もし
NOT IN
サブクエリが全く結果を返さなかった場合 (すなわち
[Order Details]
テーブルが空であることを意味します。) その場合は、そうする必要があります。私のサンプルデータの計画では、これは以下のように別のアンチセミジョインを追加することで実装されています。
その効果を示すのが Buckleyが既にリンクしているブログ記事 . この例では、論理的な読み取り回数が約400回から50万回に増加しています。
さらに、1つの
NULL
が行数をゼロにする可能性があるため、カーディナリティの推定が非常に困難になっています。SQL Server がこのような事態を想定していたとしても、実際に
NULL
行を含むデータでは、これがより大きなクエリの一部である場合、残りの実行計画が壊滅的に悪化する可能性があります。
不適切なネストされたループにより、例えば、高価なサブツリーが繰り返し実行されるような場合。
.
の実行計画はこれだけではありません。
NOT IN
の上に
NULL
-が可能なカラムです。
この記事では別のものを紹介しています
に対するクエリで
AdventureWorks2008
データベースを使用します。
については
NOT IN
の上に
NOT NULL
列または
NOT EXISTS
をNullableまたはNon nullableのカラムに対して実行すると、次のようなプランが得られます。
<イグ
に変更すると、カラムが
NULL
-を有効にします。
NOT IN
は次のようになります。
<イグ
これは、プランに余分な内部結合演算子を追加するものです。この器具は
ここで説明
. での以前の単一相関インデックスシークを変換するためにあるものです。
Sales.SalesOrderDetail.ProductID = <correlated_product_id>
を外側の行あたり2つのシークに変更しました。追加された1つは
WHERE Sales.SalesOrderDetail.ProductID IS NULL
.
これはアンチセミジョインの下にあるため、アンチセミジョインが行を返した場合、2回目のシークは起こりません。しかし、もし
Sales.SalesOrderDetail
が含まれていない場合
NULL
ProductID
の場合、必要なシーク回数が2倍になります。
関連
-
解決策:ユーザー root で localhost:3306 にある MySQL に接続できませんでした。
-
[解決済み] SQL Server テーブルにカラムが存在するかどうかを確認する方法は?
-
[解決済み] カラムの変更:NULLをNOT NULLに変更する
-
[解決済み] SQL Server にテーブルが存在するかどうかを確認する
-
[解決済み] MySQLテーブルへの挿入または存在する場合の更新
-
[解決済み] MySQLで'insert if not exists'を行うにはどうしたらいいですか?
-
[解決済み] 最初の行への結合方法
-
[解決済み] T-SQLでnot equalには!=と<>のどちらを使うべきですか?
-
[解決済み] テーブルが存在する場合、それを削除するにはどうすればよいですか?
-
[解決済み] 既存のカラムにIDを追加する
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
plsql-stored-procedure ORA-06550 エラー処理
-
MHAクラスタエラーサマリーの構築
-
SQL-初心者のためのベスト入門SQLクエリ I
-
[解決済み] SQLのカラム名があいまいな場合のクエリエラー
-
[解決済み] SQLサーバーでNULL = NULLがfalseに評価される理由
-
[解決済み] 各グループの最後のレコードを取得する - MySQL
-
[解決済み] SQL Server の VARCHAR/NVARCHAR 文字列に改行を挿入する方法
-
[解決済み] SQLiteデータベースで、一度に複数行を挿入することは可能ですか?
-
[解決済み] VARCHARとCHARの違いは何ですか?
-
[解決済み] NOT EXISTS vs. NOT IN vs. LEFT JOIN WHERE IS NULLの違いは何ですか?