2009-11-02 55 views
33

私は最近、同僚が書いたコードを読んで、SQL Serverに新しい「EXCEPT」節が存在することを知りました。それは本当に私を驚かせた!Transact SQLでNOT EXISTSではなくEXCEPTを使用するのはいつですか?

しかし、私はその使用法に関していくつか質問があります:いつ雇用することをお勧めですか? 「AND NOT EXISTS ...」を採用した相関クエリと比較クエリとの間には、パフォーマンス上の違いがありますか?

BOLでEXCEPTの記事を読んだ後は、2番目のオプションの略語だと思っていましたが、それを使っていくつかのクエリを書き直したときに驚いていました(彼らは "AND NOT EXISTS" )そして、実行計画を確認した - 驚き! EXCEPTバージョンは実行計画が短く、実行速度も速くなりました。これはいつもそうですか?

私はこの強力なツールを使用するためのガイドラインは何ですか?

+0

参考:http://explainextended.com/2009/09/15/not-in-vs-not-exists-vs -left-join-is-null-sql-server/ –

+0

@rexem:参照でEXCEPT句が決して言及されていません... –

+0

いいえ、しかしそれは存在しないことについて話しますパフォーマンス。このサイトは、dbのパフォーマンスに関する関連する質問の優れた参考資料です。 –

答えて

2

SQLサーバーの実行計画についての説明はありません。なぜなら、1つの構文が別の構文よりも優れた実行計画を立てたとき、それは完全に恣意的であるというパフォーマンスの問題が発生したときにいつも見つけました(ユーザーの観点からは、アルゴリズムの作者はその理由を理解できると確信しています)。

この場合、照会パラメーターの比較については、SQLはストレート選択ステートメントでは不可能なショートカットを把握することができます。私はそれがアルゴリズムの欠陥であると確信しています。言い換えれば、同じことを論理的に補間することはできますが、アルゴリズムは存在するクエリでその変換を行いません。時には、それを確実に把握できるアルゴリズムは、クエリ自体よりも実行に時間がかかり、あるいは少なくともアルゴリズム設計者はそう思ったからです。

33

EXCEPTは一致する値としてNULLを扱います。

このクエリ:

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
WHERE value NOT IN 
     (
     SELECT value 
     FROM p 
     ) 

は、空の行セットが返されます。

このクエリは:

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
WHERE NOT EXISTS 
     (
     SELECT NULL 
     FROM p 
     WHERE p.value = q.value 
     ) 

NULL 
1 
、この1を返します。

WITH q (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 1 
     ), 
     p (value) AS 
     (
     SELECT NULL 
     UNION ALL 
     SELECT 2 
     ) 
SELECT * 
FROM q 
EXCEPT 
SELECT * 
FROM p 

が返されます:

1 
それは奇妙な方法で振る舞うものの

再帰参照はまた、再帰CTEEXCEPT句では許可されています

WITH q (value) AS 
     (
     SELECT 1 
     UNION ALL 
     SELECT 2 
     UNION ALL 
     SELECT 3 
     ), 
     rec (value) AS 
     (
     SELECT value 
     FROM q 
     UNION ALL 
     SELECT * 
     FROM (
       SELECT value 
       FROM q 
       EXCEPT 
       SELECT value 
       FROM rec 
       ) q2 
     ) 
SELECT TOP 10 * 
FROM rec 

--- 
1 
2 
3 
-- original set 
1 
2 
-- everything except the last row of the previous set, that is 3 
1 
3 
-- everything except the last row of the previous set, that is 2 
1 
2 
-- everything except the last row of the previous set, that is 3, etc. 
1 
:それは前のセット全体ではなく、前のセットを除くすべての 最後の行以外のすべてを返します。

SQL Server開発者は、これを禁止することを忘れてしまったばかりです。

+0

また、 'except'はSetを返します。したがって、異なる値を返します。 – Magnus

2

EXCEPTは、2つのフル・セレクトのすべての(ペアになった)列を比較します。 NOT EXISTSは、NOT EXISTSキーワードに続くサブクエリのWHERE句で指定された条件に一致する2つ以上のテーブルを比較します。

NOT EXISTSを使用してEXCEPTを書き換えることができます。 (ALLが存在するROW_NUMBERを使用しないことによって書き換えることができる点が異なります。)

は、私は除いての分析の多くを行っている、存在しないhere

8

からこれを持っていないでと外部結合左。一般的に、左外部結合は、欠落した行を見つけるために最も速く、特に主キーで結合します。選択肢に返された小さなリストになることがわかっている場合、Not Inは非常に高速になります。

コードを書き換えるときに返される内容を比較するために、EXCEPTを使用します。結果を保存する古いコードを実行します。新しいコードを実行して結果を保存し、次にexceptを使用してすべての相違点をキャプチャします。これは、特にnullを含むすべての相違点を取得する必要がある場合は、違いを見つけるための非常に迅速かつ簡単な方法です。非常に良いフライで簡単にコーディングしてください。

ただし、すべての状況が異なります。私がこれまでに指導したすべての開発者に言います。それを試してみてください。タイミングはすべて異なった方法で行います。試してみてください。

2

クエリが細かく調整されていれば、EXCEPT句とNOT EXIST/NOT INを使用してパフォーマンスの違いはありません。相関クエリを変更してEXCEPTを実行したときにはじめてです。相関関係のあるクエリが22秒で戻ってきた間に、結果はちょうど7秒で返されました。次に、相関クエリとreranにdistinct句が使用されました。それも7秒後に返されました。そうでない場合は、両方のパフォーマンスが同じであることを確認してください。

関連する問題