4

次の(簡略化された)CTEを試しています。テーブル変数 () を使用すると、クエリをキャンセルする前に数分間クエリが実行されます。他のコメントアウトされたメソッドはいずれも、1 秒以内に戻ります。

WHERE 句全体を INNER JOIN に置き換えると、同様に高速になります。

テーブル変数を使用すると実行速度が非常に遅くなる理由はありますか?

FWIW: データベースには 250 万のレコードが含まれており、内部クエリは 2 つのレコードを返します。

CREATE TABLE #rootTempTable (RootID int PRIMARY KEY)
INSERT INTO #rootTempTable VALUES (1360);

DECLARE @rootTableVar TABLE (RootID int PRIMARY KEY);
INSERT INTO @rootTableVar VALUES (1360);

WITH My_CTE AS 
(
      SELECT ROW_NUMBER() OVER(ORDER BY d.DocumentID) rownum, d.DocumentID, d.Title
      FROM [Document] d
      WHERE d.LocationID IN 
        (
              SELECT LocationID 
              FROM Location 
                    JOIN @rootTableVar rtv ON Location.RootID = rtv.RootID -- VERY SLOW!
                    --JOIN #rootTempTable tt ON Location.RootID = tt.RootID -- Fast
                    --JOIN (SELECT 1360 as RootID) AS rt ON Location.RootID = rt.RootID -- Fast
                    --WHERE RootID = 1360 -- Fast
        )           
) 
SELECT * FROM My_CTE WHERE (rownum > 0) AND (rownum <= 100) ORDER BY rownum

これは、テーブル変数を使用する場合からのものです。クエリの実行には 17 分以上かかりました。 ここに画像の説明を入力

XML 形式の実行計画

一時テーブル: https://docs.google.com/open?id=0B66I-fxlyEtEZEthV3ZaWlNLWXM

テーブル変数: https://docs.google.com/open?id=0B66I-fxlyEtEbUFZa3RJejFCTkk

4

2 に答える 2

4

クエリ プランで明らかになったのは、テーブル変数バージョンが、悪名高い「テーブル変数カーディナリティ推定」の問題に苦しんでいることです。これは主に、一時テーブルとは異なり、テーブル変数が統計をサポートしていないために発生します。ポール・ホワイトによるこの記事では、それを非常に詳細に説明しています。

https://sqlkiwi.blogspot.com/2012/08/temporary-tables-in-stored-procedures.html

また、最も簡単な解決策はおそらくOPTION (Recompile);クエリの最後に句を追加することであることも明らかです。これは以前のバージョンの SQL Server では機能しない可能性がありますが、新しいバージョンではカーディナリティの見積もりが向上し、一時テーブル バージョンと同じクエリ プランが生成されるはずです。

他の (あまり望ましくない) 可能な解決策があるため、これが機能しない場合はお知らせください。

于 2012-11-05T17:12:38.360 に答える
0

部分的な解決策: インデックスの物理統計レポートを使用して、SQL Server の推奨に従ってテーブルのインデックスを再構築または再編成すると、非常に役立ちました。このレポートは、データベースを右クリックして [レポート] > [標準レポート] > [インデックスの物理統計] を選択すると表示されます。

于 2012-11-07T00:23:00.697 に答える