web-dev-qa-db-ja.com

Transact SQLでNOT EXISTSではなくEXCEPTを使用する場合

私は最近、同僚が書いたコードを読むことで、SQL Serverに新しい "EXCEPT"句が存在することを知りました(少し遅くなりましたが...)。本当にびっくりしました!

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

BOLのEXCEPTの記事を読んだ後、それは2番目のオプションの単なる省略形であると思ったが、それを使用していくつかのクエリを書き直したときは驚いた実行計画-サプライズ! EXCEPTバージョンは実行プランが短く、実行も高速でした。これはいつもそうですか?

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

38
Joe Pineda

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

、そしてこれ:

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

再帰参照は、再帰EXCEPTCTE句でも許可されますが、奇妙な方法で動作します。前のセットの最終行を除くすべてを返します。前のセット全体を除くすべてではありません:

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開発者はそれを禁止することを忘れたに違いありません。

37
Quassnoi

私は多くの分析を行いましたが、存在しない、存在しない、外部結合を残しました。通常、左外部結合は、特に主キーでの結合の欠落行を見つけるのに最も高速です。 Not Inは、selectで返される小さなリストであることがわかっている場合、非常に高速です。

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

しかし、すべての状況は異なります。私が指導したすべての開発者に言います。それを試してみてください。さまざまな方法で計時を行います。試して、時間をかけて、やってください。

8
Linda Warner

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

EXCEPTは、NOT EXISTSを使用して書き換えることができます。 (EXCEPT ALLは、ROW_NUMBERおよびNOT EXISTSを使用して書き換えることができます。)

here からこれを手に入れました

3
priyanka.sarkar

クエリが微調整されている場合、EXCEPT句とNOT EXIST/NOT INを使用してもパフォーマンスの違いはありません。相関クエリを変更してから初めてEXCEPTを実行したとき。相関クエリが22秒で戻ってきたときに、わずか7秒で結果が得られました。その後、相関クエリで個別の句を使用して再実行しました。また、7秒で戻りました。クエリを微調整する時間があります。そうしないと、両方のパフォーマンスが同じになります。

2
Adil Aleem

SQLサーバーの実行計画のアカウンティングはありません。パフォーマンスの問題があるとき、ある構文が別の構文よりも優れた実行計画を作成したとき、それはまったくfrom意的であることが常にわかりました(ユーザーの観点から、アルゴリズム作成者はその理由を理解するはずです)。

この場合、クエリパラメーターの比較についての何かを使用すると、SQLは、単純なselectステートメントではできないショートカットを見つけることができます。これはアルゴリズムの欠陥だと確信しています。言い換えれば、同じものを論理的に補間することはできますが、アルゴリズムは既存のクエリでその変換を行いません。時には、それを確実に把握できるアルゴリズムは、クエリ自体よりも実行に時間がかかるか、少なくともアルゴリズム設計者がそう考えたためです。

2
Yishai