130,000行のテーブル_dbo.ClaimBilling
_があります。この表では、列OperatorID
はvarchar(max)
であり、大きく歪んでいます。 125,000行は「user1」であり、残りの5000行は6つの他の値に分割され、「user2」は合計3つのレコードを持ちます。
OperatorID
には非クラスター化インデックスがあり、クラスター化インデックスは主キーIDClaimBilling
です。
現在、次のクエリがあります。
_SELECT DISTINCT IDClaimBilling
FROM dbo.ClaimBilling cb
INNER JOIN dbo.BillingItem bi
ON cb.IDClaimBilling = bi.ClaimID
WHERE OperatorID = @operator
_
_@operator
_の値に関係なく、ClaimBilling
からの行の推定値は〜4000であり、これはどの値が返すものにも近くなく、常にクラスター化インデックススキャンであり、使用しません。 operatorID
インデックス。結合を削除して実行すると
_SELECT DISTINCT IDClaimBilling
FROM dbo.ClaimBilling
WHERE OperatorID = @operator
_
次に、OperatorID
インデックスを使用しますが、_@operator
_の値に関係なく、推定は間違っています。今回は常に約18,000程度を推定しています。
クエリを実行する前に_UPDATE STATISTICS dbo.ClaimBilling WITH FULLSCAN
_を実行しました。
統計が値あたりの行数を正確に知っているのに、これらの推定値がそれほど間違っているのはなぜですか?
テストでは、値を宣言して_@operator
_に割り当てています。もともとはプロシージャの一部でしたが、それが問題だと思いましたが、アドホックステートメントで使用した場合も同じように動作します。
クエリはユーザーが最初にログインしたときにのみ実行されるため、ユーザーごとに1日に数回しか実行されません。
質問に残されたコメントから生成されたコミュニティWiki回答
_@operator
_を変数として使用してクエリを実行している場合、SQL Serverは変数の値を「傍受」できないため、統計の平均密度値を使用して推定値を計算します。変数に割り当てる値に関係なく、この平均値の見積もりは常に同じになります。
これを解決する1つの方法は、OPTION (RECOMPILE)
クエリヒントを使用することです。これにより、実行時に変数の特定の値に最適化された計画で、実行ごとに新しい計画がコンパイルされます。これには、ステートメントを再コンパイルするたびに(通常は小さい)コストがかかります。
コードをモジュール化することもできます。 IF
ステートメントを使用してoperatorid
の値を確認し、「user1」が1つのストアドプロシージャを呼び出す場合は、_sp_user1
_としましょう。 「user1」でない場合は、別のプロシージャを呼び出します。最初のspは「user1」用に最適化され、残りの値は残りの値用に最適化されます。必要に応じて、「user1」以外の値に対して2番目のspでoption (recompile)
を使用することもできます。
また、動的SQLの適切な使用例になる場合もあります。これにより、_@operator
_変数がリテラル値に変わり、各ユーザーの計画がカスタマイズされます。そのテーブルには7人のユーザーしかいないので、それが本当に問題になるとは思いません。
詳細については、以下を参照してください。
wikiの回答 は正解で、非常に徹底的になっています。しかし、私はこれを捨てるつもりです... where句をあなたの結合に移動します:
SELECT DISTINCT IDClaimBilling
FROM dbo.ClaimBilling cb
INNER JOIN dbo.BillingItem bi
ON cb.IDClaimBilling = bi.ClaimID
and cb.OperatorID = @operator
または、多分あなたが見てきたサブクエリで結合します。
SELECT DISTINCT IDClaimBilling
FROM (select IDCLaimBilling from dbo.ClaimBilling where OperatorID = @operator) cb
INNER JOIN dbo.BillingItem bi
ON cb.IDClaimBilling = bi.ClaimID
そして https://www.brentozar.com/pastetheplan/ を使用して計画を貼り付けます。