結合述語で変数を参照すると、ネストされたループが強制されるのはなぜですか?


16

最近この問題に遭遇しましたが、オンラインで議論することができませんでした。

以下のクエリ

DECLARE @S VARCHAR(1) = '';

WITH T
     AS (SELECT name + @S AS name2,
                *
         FROM   master..spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2;

ネストされたループ計画を常に取得します

ここに画像の説明を入力してください

問題INNER HASH JOINまたはINNER MERGE JOINヒントで問題を強制しようとすると、次のエラーが生成されます。

このクエリで定義されたヒントのため、クエリプロセッサはクエリプランを作成できませんでした。ヒントを指定せずに、SET FORCEPLANを使用せずに、クエリを再送信します。

ハッシュ結合またはマージ結合の使用を許可する回避策を見つけました-変数を集約にラップします。生成された計画は大幅に低コストです(19.2025対0.261987)

DECLARE @S2 VARCHAR(1) = '';

WITH T
     AS (SELECT name + (SELECT MAX(@S2)) AS name2,
                *
         FROM   spt_values)
SELECT *
FROM   T T1
       INNER JOIN T T2
         ON T1.name2 = T2.name2; 

ここに画像の説明を入力してください

この動作の理由は何ですか?そして、私が見つけたものよりも良い回避策がありますか?(おそらく、追加の実行計画ブランチは必要ありません)

回答:


13

SQL 2012インスタンスでクエリを試行しましたが、トレースフラグ4199は問題を修正しているようです。これを有効にすると、合計コストが0.24のマージ結合が得られ、余分なブランチはありません。

この問題に関する特定のKB記事は、クエリの結合述語にSQL Server 2005またはSQL Server 2008の外部参照列がある場合にパフォーマンスの問題が発生することです。

ここに画像の説明を入力してください

さらに認定するために、TF 4199はすべてのオプティマイザーの修正を有効にします。詳細については、このリンクを参照してください。すべてを一度に有効にすると、奇妙な副作用が発生する可能性があります。そのため、特定の修正を見つけることができる場合は、それ自体で修正を有効にする方が良い場合があります。

クエリごとにトレースフラグを有効にできます。 OPTION (QUERYTRACEON 4199)、。


0

古い質問ですが、答えを見ることは非常に決定的なものではなかったので、見つけた回避策を投稿すると思いました。クエリオプティマイザーがなぜをブロックするのかはわかりませんが、ソートされた入力がないためHASH気に入らないと思いMERGEます。2012/14に、

DECLARE @S VARCHAR(1) = '';

    WITH T
        AS (SELECT TOP (2147483647)
                name + @S AS name2,
                *
            FROM   master..spt_values
            ORDER BY name + @S)
    SELECT *
    FROM   T T1
           INNER JOIN T T2
             ON T1.name2 = T2.name2;

次の計画を作成します。

ここに画像の説明を入力してください

強制TOPORDER BYcteで、オプティマイザにデータセットについての十分な知識を提供するようMERGE JOINです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.