7

ひどく実行するストアドプロシージャがあります。変数を宣言するときは、その値を設定してから、ステートメントの実行に1時間以上かかるwhere句で使用します。where句の変数をハードコーディングすると、1秒未満で実行されます。

私は実行計画を通してそれの何が悪いのかを調べ始めました。UNIONと共通テーブル式を使用するビューから値を選択するため、いくつかの宣言された変数を渡そうとすると、実行プランはいくつかのハッシュ一致を作成するように見えます。

/*************ストアドプロシージャの開始***************/
手順の作成GetFruit
  @ColorId bigint、
  @SeasionId bigint
再コンパイルあり
なので
始める

選択する
    名前
から
    [Apple_View] A/*これは下のビューです*/
    インナージョイント[フルーツ]F
        オン(F.ColorId = @ColorId
            AND A.FruitId = F.FruitId)          
どこ
    (A.ColorId = @ColorId
    と
    A.SeasonId = @SeasonId)

終わり
/*************ストアドプロシージャの終了***************/

/*************ビューの開始***************/
果物付き(FruitId、ColorId、SeasonId)AS
((
    -アンカーメンバー
    選択する
        F.FruitId
        、F.ColorId
        、F.SeasonId
    から
        (((  
            距離を選択
                EF.FruitId
                、EF.ColorId
                、EF.SeasonId
                、EF.ParentFruitId
            から
                エキゾチックフルーツEF
                インナージョインフルーツFR
                    ON FR.FruitId = EF.FruitId
        連合
            距離を選択
                SF.FruitId
                、SF.ColorId
                、SF.SeasonId
                、SF.ParentFruitId               
            から
                StinkyFruit SF
                インナージョインフルーツFR
                    ON FR.FruitId = SF.FruitId
        連合
            距離を選択
                CF.FruitId
                、CF.ColorId
                、CF.SeasonId
                、CF.ParentFruitId
            から
                CrazyFruit CF
                インナージョインフルーツFR
                    ON FR.FruitId = CF.FruitId

            ))f

    ユニオンオール

    -再帰的な親の果実
    選択する
        FS.FruitId
        、FS.ColorId
        、FS.SeasonId
        、FS.ParentFruitId
    から
        フルーツFS
        内部結合MasterFruitMF
            ONMF。[ParentFruitId]=fs。[FruitId]
)。

距離を選択
    FS.FruitId
    、FS.ColorId
    、FS.SeasonId
    から
        フルーツFS

/*************ビューの終わり***************/


/*実行するには*/
EXEC GetFruit 1,3

設定値を使用してストアドプロシージャを実行すると、1時間以上かかります。これが、実行プランです。 変数付き

DECLARE値とSET値を削除してストアドプロシージャを実行し、Where句を次のステートメントに設定すると、1秒未満で実行され、実行プランは次のようになります。

WHERE(A.ColorId = 1 AND  A.SeasonId = 3)

ハードコードされたwhere句

最初の変数がハッシュセットを使用しているのに対し、ハードコードされた変数がどのようにインデックスを使用しているかに注目してください。何故ですか?where句のハードコードされた値が宣言された変数と異なるのはなぜですか?

-------これは@user1166147の助けを借りて最終的に実行されたものです------

sp_executesqlを使用するようにストアドプロシージャを変更しました。

手順の作成GetFruit
  @ColorId bigint、
  @SeasionId bigint
再コンパイルあり
なので
始める

DECLARE @SelectString nvarchar(max)

SET @SelectString = N'SELECT
    名前
から
    [Apple_View] A/*これは下のビューです*/
    インナージョイント[フルーツ]F
        オン(F.ColorId = @ColorId
            AND A.FruitId = F.FruitId)          
どこ
    (A.ColorId ='+ CONVERT(NVARCHAR(MAX)、@ColorId)+'
    と
    A.SeasonId ='+ CONVERT(NVARCHAR(MAX)、@SeasonId)+') '

EXEC sp_executesql @SelectString

終わり
4

2 に答える 2

2

概要の編集 Damien_The_Unbelieverからのリクエストごと

目標は、プランが作成される前に、変数値に関する最良/ほとんどの情報をSQLに取得することです。通常、パラメータースニッフィングがこれを行います。この場合、パラメータスニッフィングが「無効」にされた理由がある可能性があります。実際のコードのより良い表現を見なければ、解決策が何であるか、または問題が存在する理由を実際に言うことはできません。以下のことを試して、影響を受ける領域に実際の値を使用して計画を生成させます。

*より詳細なロングバージョン*

これは実際のストアドプロシージャですか?パラメータのデフォルト値はありますか?もしそうなら、彼らは何ですか?

パラメータスニッフィングは役立ちますが、プランを適切に作成するには、一般的なパラメータ値が必要です。そうでない場合、実際には役に立たないか、非一般的なパラメータ値に基づいて不適切なプランが作成されます。したがって、変数のデフォルト値がnullであるか、最初に実行されてプランがコンパイルされたときに一般的な値ではない値である場合、悪いプランが作成されます。

他の誰かがこのsprocを書いた場合、理由のためにローカル変数をスニッフィングするパラメータを意図的に「無効」にした可能性があります。ビジネスルールでは、これらの可変構造が必要になる場合があります。

目標は、計画が作成される前にSQLに変数値に関する最良/ほとんどの情報を取得することであり、通常、パラメータースニッフィングがこれを行います。ただし、パフォーマンスに悪影響を与える可能性があるため、「無効」になっている可能性があります。計画はまだパラメータの非定型値で作成されているか、まだ十分な情報がないようです-パラメータスニッフィングを使用しているかどうか。

[sp_executesqlを使用して]を使用してsproc内のクエリを呼び出して、影響を受けるクエリを実行し、実際の変数を使用してその領域の計画を生成するように強制し、それが優れているかどうかを確認してください。変数が標準値を受け取った後、この種の不規則なパラメータ値(影響を受ける部分を実行するストアドプロシージャを作成し、後でストアドプロシージャ内から呼び出す)が必要な場合は、これが解決策になる可能性があります。

実際のコードのより良い表現を見なければ、問題が何であるかを理解することは困難です。うまくいけば、この情報が役立つでしょう-

于 2012-06-20T13:31:22.283 に答える
0

よく知っている可能性のある一般的な値に基づいて、クエリを最適化するように強制できます。元のクエリに次を追加します。

OPTION (OPTIMIZE FOR(@ColorId = 1, @SeasionId = 3))

動的SQLがなくても同様の効果があります。一般的な値がわからない場合は、オプティマイザにそれらをスニッフィングさせることができます。

OPTION (OPTIMIZE FOR UNKNOWN)

繰り返しますが、動的SQLはありません

于 2012-07-04T19:30:26.837 に答える