6

パラメーター化されたクエリからパラメーター化されていないクエリに変更したときの、SQL Server でのステートメントの推定クエリ プランの動作を理解するのに苦労しています。

次のクエリがあります。

DECLARE @p0 UniqueIdentifier = '1fc66e37-6eaf-4032-b374-e7b60fbd25ea'
SELECT [t5].[value2] AS [Date], [t5].[value] AS [New]
FROM (
    SELECT COUNT(*) AS [value], [t4].[value] AS [value2]
    FROM (
        SELECT CONVERT(DATE, [t3].[ServerTime]) AS [value]
        FROM (
            SELECT [t0].[CookieID]
            FROM [dbo].[Usage] AS [t0]
            WHERE ([t0].[CookieID] IS NOT NULL) AND ([t0].[ProductID] = @p0)
            GROUP BY [t0].[CookieID]
            ) AS [t1]
        OUTER APPLY (
            SELECT TOP (1) [t2].[ServerTime]
            FROM [dbo].[Usage] AS [t2]
            WHERE ((([t1].[CookieID] IS NULL) AND ([t2].[CookieID] IS NULL)) 
            OR (([t1].[CookieID] IS NOT NULL) AND ([t2].[CookieID] IS NOT NULL) 
            AND ([t1].[CookieID] = [t2].[CookieID]))) 
            AND ([t2].[CookieID] IS NOT NULL)          
            AND ([t2].[ProductID] = @p0)
            ORDER BY [t2].[ServerTime]
            ) AS [t3]
        ) AS [t4]
    GROUP BY [t4].[value]
    ) AS [t5]
ORDER BY [t5].[value2]

このクエリは、Linq2SQL 式によって生成され、LINQPad から抽出されます。これにより、(私が知る限り)適切なクエリ プランが生成され、データベース上で約 10 秒で実行されます。ただし、パラメーターの 2 つの使用を正確な値に置き換えると、つまり、2 つの '= @p0' 部分を '= '1fc66e37-6eaf-4032-b374-e7b60fbd25ea' に置き換えます。クエリの実行時間が大幅に長くなりました (60 秒以上、まだ確認していません)。

一見無害に見える置換を実行すると、クエリ プランと実行の効率が大幅に低下するのはなぜでしょうか? 'DBCC FreeProcCache' でプロシージャ キャッシュをクリアして、不適切なプランをキャッシュしていないことを確認しましたが、動作は残ります。

私の本当の問題は、10 秒の実行時間 (少なくともしばらくの間) には耐えられますが、60 秒以上の実行時間には耐えられないことです。私のクエリは(上記のように)Linq2SQLによって生成されるため、データベースで次のように実行されます

exec sp_executesql N'
        ...
        WHERE ([t0].[CookieID] IS NOT NULL) AND ([t0].[ProductID] = @p0)
        ...
        AND ([t2].[ProductID] = @p0)
        ...
       ',N'@p0 uniqueidentifier',@p0='1FC66E37-6EAF-4032-B374-E7B60FBD25EA'

これは同じように実行時間が長くなります(これは、パラメーター化されたクエリを使用しているように見えるため、二重に奇妙だと思います.

どのインデックスを作成するかなどについてアドバイスを求めているわけではありません。一見似ているように見える3つのクエリでクエリプランと実行がなぜそれほど異なるのかを理解しようとしているだけです。

編集:パラメータ化されていないクエリとパラメータ化されたクエリの実行計画、および別の GUID を使用してパラメータ化されたクエリの実行計画 ( Heinzが提案) をアップロードしました。

それが私を助けるのに役立つことを願っています:)

4

4 に答える 4

3

明示的な値を指定すると、SQL Server はこのフィールドの統計を使用して、"より良い" クエリ プランを決定できます。残念なことに (私自身が最近経験したように)、統計に含まれる情報が誤解を招く場合、SQL Server が間違った選択をすることがあります。

この問題をより深く掘り下げたい場合は、他の GUID を使用するとどうなるかを確認することをお勧めします。異なる具体的な GUID に対して異なるクエリ プランを使用する場合、それは統計データが使用されていることを示しています。その場合は、sp_updatestatsおよび関連するコマンドを参照することをお勧めします。

編集: DBCC SHOW_STATISTICSを見てください:「遅い」GUID と「速い」GUID は、おそらくヒストグラムの異なるバケットにあります。同様の問題がありましたが、INDEXテーブル ヒントを SQL に追加することで解決しました。これにより、SQL Server が「適切な」クエリ プランを見つけるように「ガイド」されます。基本的に、「高速」クエリで使用されるインデックスを調べ、それらを SQL にハードコーディングしました。これは最適またはエレガントな解決策とはほど遠いですが、私はまだより良い解決策を見つけていません...

于 2009-11-03T13:03:24.157 に答える
2

どのインデックスを作成するかなどについてアドバイスを求めているわけではありません。一見似ているように見える3つのクエリで、クエリプランと実行がなぜそれほど異なるのかを理解しようとしているだけです。

2 つのインデックスがあるようです。

IX_NonCluster_Config (ProductID, ServerTime)
IX_NonCluster_ProductID_CookieID_With_ServerTime (ProductID, CookieID) INCLUDE (ServerTime)

最初のインデックスはカバーしていませんCookieIDが、順序付けられているため、選択性の低いもの (つまり、多くのもの) のServerTime方が効率的です。ProductID

2 番目のインデックスはすべての列をカバーしますが、順序付けされていないため、より選択的なProductID's (数が少ないもの) の方が効率的です。

平均して、ProductIDカーディナリティはSQL Server、2 番目の方法が効率的であると期待するためのものです。これは、パラメーター化されたクエリを使用するか、明示的に選択的を提供するときに使用するものですGUID

ただし、オリジナルGUIDは選択性が低いと見なされるため、最初の方法が使用されます。

残念ながら、最初の方法では追加のフィルタリングが必要にCookieIDなるため、実際には効率が低下します。

于 2009-11-03T14:11:02.873 に答える
1

私の推測では、パラメーター化されていないルートを使用する場合、guid を varchar から UniqueIdentifier に変換する必要があるため、インデックスが使用されない可能性がありますが、パラメーター化されたルートでは使用されます。

datetime を使用する列に対して where 句に smalldatetime を持つクエリを使用すると、これが発生するのを見てきました。

于 2009-11-03T12:58:19.353 に答える
0

実行計画を見ずに判断するのは難しいですが、理由を推測するなら、パラメータ スニッフィングと貧弱な統計の組み合わせだと思います。GUID をクエリにハードコーディングした場合、クエリ オプティマイザーは、パラメーターのその値に対してクエリを最適化しようとします。パラメータ化された/準備されたクエリでも同じことが起こると思います(これはパラメータスニッフィングと呼ばれます-準備されたステートメントが初めて実行されるときに使用されるパラメータに対して実行計画が最適化されます)が、これは宣言するときは絶対に起こりませんパラメータをクエリで使用します。

前述のように、SQL サーバーはその値の実行計画を最適化しようとするため、通常はより良い結果が得られるはずです。ここでは、決定の基になっている情報が正しくない/誤解を招くように思われます。一般的なパラメーター値のクエリを最適化すると、(何らかの理由で) より良い結果が得られます。

これはほとんど当て推量ですが、実際に実行しないと判断できません。実行計画をどこかにアップロードできれば、誰かが本当の理由を教えてくれるはずです。

于 2009-11-03T13:25:24.283 に答える