クエリは
SELECT SUM(Amount) AS SummaryTotal
FROM PDetail WITH(NOLOCK)
WHERE ClientID = @merchid
AND PostedDate BETWEEN @datebegin AND @dateend
テーブルには103,129,000行が含まれています。
高速プランは、日付の残存述部を使用してClientIdでルックアップしますが、を取得するには96回のルックアップを行う必要がありますAmount
。<ParameterList>
計画のセクションは次のとおりです。
<ParameterList>
<ColumnReference Column="@dateend"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@datebegin"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@merchid"
ParameterRuntimeValue="(78155)" />
</ParameterList>
遅いプランは日付で検索し、ClientIdの残りの述語を評価して量を取得するためのルックアップを持っています(推定1対実際7,388,383)。<ParameterList>
セクションです
<ParameterList>
<ColumnReference Column="@EndDate"
ParameterCompiledValue="'2013-02-01 23:59:00.000'"
ParameterRuntimeValue="'2013-02-01 23:59:00.000'" />
<ColumnReference Column="@BeginDate"
ParameterCompiledValue="'2013-01-01 00:00:00.000'"
ParameterRuntimeValue="'2013-01-01 00:00:00.000'" />
<ColumnReference Column="@ClientID"
ParameterCompiledValue="(78155)"
ParameterRuntimeValue="(78155)" />
</ParameterList>
この2番目のケースでParameterCompiledValue
は、は空ではありません。SQL Serverは、クエリで使用される値をスニッフィングしました。
著書「SQL Server 2005の実用的なトラブルシューティング」、これはローカル変数を使用してについて言いたいことがあります
ローカル変数を使用してパラメータースニッフィングを無効にすることはかなり一般的なトリックですが、OPTION (RECOMPILE)
およびOPTION (OPTIMIZE FOR)
ヒント...は一般に、よりエレガントでリスクの少ないソリューションです
注意
SQL Server 2005では、ステートメントレベルのコンパイルにより、ストアドプロシージャ内の個々のステートメントのコンパイルを、クエリの最初の実行の直前まで延期できます。それまでに、ローカル変数の値がわかります。理論的には、SQL Serverはこれを利用して、パラメーターをスニッフィングするのと同じ方法でローカル変数値をスニッフィングできます。ただし、SQL Server 7.0およびSQL Server 2000+ではローカル変数を使用してパラメータースニッフィングを無効にするのが一般的であったため、SQL Server 2005ではローカル変数のスニッフィングは有効になりませんでした。選択肢がある場合は、この章で概説する他のオプションのいずれかを使用する理由。
この目的のための簡単なテストから、上記の動作は2008と2012で同じであり、変数は遅延コンパイル用にスニッフィングされませんが、明示的なOPTION RECOMPILE
ヒントが使用される場合のみです。
DECLARE @N INT = 0
CREATE TABLE #T ( I INT );
/*Reference to #T means this statement is subject to deferred compile*/
SELECT *
FROM master..spt_values
WHERE number = @N
AND EXISTS(SELECT COUNT(*) FROM #T)
SELECT *
FROM master..spt_values
WHERE number = @N
OPTION (RECOMPILE)
DROP TABLE #T
遅延コンパイルにもかかわらず、変数はスニッフィングされず、推定行カウントは不正確です
したがって、スロープランはクエリのパラメーター化されたバージョンに関連していると想定しています。
これParameterCompiledValue
はParameterRuntimeValue
すべてのパラメーターのに等しいため、これは一般的なパラメータースニッフィングではありません(1つの値セットに対して計画がコンパイルされ、別の値セットに対して実行されます)。
問題は、正しいパラメーター値用にコンパイルされたプランが不適切であることです。
こことここで説明されている昇順の日付で問題が発生している可能性があります。1億行のテーブルでは、SQL Serverが自動的に統計を更新する前に、2000万行を挿入(または変更)する必要があります。最後に更新された行はクエリの日付範囲と一致していなかったようですが、現在では700万行が一致しています。
統計情報の更新をより頻繁にスケジュールし2389 - 90
たり、トレースフラグを検討したりOPTIMIZE FOR UKNOWN
、datetime
列で現在誤解を招く統計情報を使用したりせずに推測に基づいてフォールバックすることもできます。
これは、SQL Serverの次のバージョン(2012年以降)では必要ない場合があります。関連の接続項目は、魅力的な応答が含まれています
Microsoftによる2012年8月28日午後1:35の投稿
次のメジャーリリースで、これを本質的に修正するカーディナリティ推定の強化を行いました。プレビューが公開されたら、詳細にご注目ください。エリック
この2014年の改善は、記事の終わり頃にベンジャミンネバレスによって検討されています。
新しいSQL Serverのカーディナリティ見積もりでA初見。
この場合、新しいカーディナリティー推定器はフォールバックし、1行の推定値を与えるのではなく、平均密度を使用するようです。
2014年のカーディナリティ推定量と昇順の重要な問題に関する追加の詳細は次のとおりです。
SQL Server 2014の新機能–パート2 –新しいカーディナリティの推定