2

私はいくつかのSQLクエリを最適化しており(これは私が最近投稿した質問のパート2と見なすことができます)、いくつかのNOTINをNOTEXISTS述語に置き換えています

そうすることの主な利点は、NOT EXISTSを使用すると、単一の一致が見つかったときにステートメントが終了するという利点が得られることですが、カウントサブクエリを使用したNOT INは、全表スキャンを実行する必要があると思いますか?

また、選択したデータにNULLが含まれている場合、NOT INにも追加の作業が必要になるようですが、これは正しいですか?

procに実装する前に、これら2つのケースで2番目のステートメントが最初のステートメントよりも優れている(そして機能的に同等である)ことを確認する必要があります。

ケース1:

        --exclude sessions that were tracked as part of a conversion during the last response_time minutes
        -- AND session_id NOT IN (SELECT DISTINCT tracked_session_id    
        --                              FROM data.conversions WITH (NOLOCK)
        --                              WHERE client_id = @client_id
        --                              AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
        --                              AND utc_date_completed <= @date     
        --                              AND utc_date_clicked <= @date)

        AND NOT EXISTS (SELECT 1
                            FROM data.conversions WITH (NOLOCK)
                            WHERE client_id = @client_id
                            AND utc_date_completed >= DATEADD(minute, (-2) * cy.response_time, @date)
                            AND utc_date_completed <= @date
                            AND utc_date_clicked <= @date
                            AND data.conversions.tracked_session_id = d.session_id
        )

ケース2:

        -- NOT EXISTS vs full table scan with COUNT(dashboard_id)                                   
        -- AND (SELECT COUNT(dashboard_id)
        --          FROM data.dashboard_responses WITH(NOLOCK)
        --          WHERE session_id = d.session_id
        --          AND cycle_id = cy.id
        --          AND client_id = @client_id) = 0

        AND NOT EXISTS(SELECT 1
                            FROM data.dashboard_responses
                            WHERE session_id = d.session_id
                            AND cycle_id = cy.id
                            AND client_id = @client_id)

乾杯

4

2 に答える 2

5

あなたが正しく言ったように、2つは異なるものです。含まれないアイテムのサブクエリにIN含まれないものがない場合、何も等しくなく、何も等しくない(NULLでさえない)NULLため、結果は返されません。NULLNULL

同じ結果を達成するために2つを使用していると仮定すると、ステートメントNULLで値を処理する限り、2つの間に違いはありません。INオプティマイザーは、値が削除されているか、null許容でない列があれば、2つが同じであることを理解するのに十分賢いNULLので、同じを使用しANTI SEMI JOINます。

次の2つの表を検討してください。

CREATE TABLE T (ID INT NOT NULL PRIMARY KEY);
CREATE TABLE T2 (ID INT NOT NULL PRIMARY KEY);

これらの2つのクエリは、まったく同じ実行プランを取得します。

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T2);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T2 WHERE T.ID = T2.ID);

オプティマイザーはT2.IDがNULL可能でない列であることを知っているためです。3番目のテーブル:

CREATE TABLE T3 (ID INT);

ID列にインデックスが付けられておらず、null許容でもない場合、これら2つのクエリは非常に異なる実行プランをレンダリングします。

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T3);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID);

NOTEXISTSの方がはるかに効率的です。ただし、これら2つは、(基本的に)同じ実行プランを生成します。

SELECT  *
FROM    T
WHERE   ID NOT IN (SELECT ID FROM T3 WHERE T3.ID IS NOT NULL);

SELECT  *
FROM    T
WHERE   NOT EXISTS (SELECT ID FROM T3 WHERE T.ID = T3.ID);

これらのクエリとサンプルデータはすべてSQLFiddleにあります

編集

実際にあなたの質問に答えるには:

ケース1NOT INは、のまたはNOT EXISTSiftracked_session_idがnull許容でない列と同じパフォーマンスになるか、Inステートメント内にdata.conversions追加します。WHERE tracked_Session_id IS NOT NULL列がnull許容でなく、null値を除外しない場合、パフォーマンスは同じになりません。nullがないと仮定すると、パフォーマンスが向上します。nullNOT EXISTSがない場合、結果は同じにならないため、パフォーマンスは次のようになります。比較できません。

ケース2は実際にサンプルデータで私を驚かせました、これはに最適化されないと思い、ANTI SEMI JOINすでに同じくらいの答えを書いていましたが、編集を保存する直前に私はチェックしたほうがいいと思い、見て驚いたこれ:

SELECT  *
FROM    T
WHERE   (   SELECT  COUNT(*) 
            FROM    T3
            WHERE   T.ID = T3.ID
        ) = 0;

とまったく同じように最適化されNOT EXISTSます。したがって、オプティマイザーは私が思っていたよりもさらに賢いようです。カウントを0以外にしたい場合にのみ、異なるプランが生成されます。

ケース2のSQLフィドル

于 2013-01-23T12:08:40.203 に答える
2

nullとは大きな違いがあるのは正しいです。クエリは、各要素がNOT IN完全に一致しないことを確認します。nullとの比較では、決定的な結果は得られません。したがって、サブクエリにnullが含まれている場合、それは「NOT IN」とは見なされません。

このSQLFiddleの例を参照してください。

この動作の直感的でない副作用は、NOT IN実際にはの反対ではないということですIN

クエリにはこのNOT EXISTS問題はありません。

多くの場合、どのような種類の最適化が行われるかに依存するため、どちらがより優れたパフォーマンスを発揮するかについて、包括的な声明を出すことを躊躇します。そのため、パフォーマンスを重視する場合は、実行プランを見つけることが重要です。

于 2013-01-23T11:59:46.117 に答える