web-dev-qa-db-ja.com

統計は更新されていますが、推定行数と実際の行数は同じではありません

SELECTステートメントを実行して、27451373行のテーブルからdatetime列にフィルターを適用した2つの列を取得しています。

declare @LastProcessedDate datetime='08-15-2016'

select Bill_Code,CLIENT_ID_6,u2_id
from [ODS_HRP].dbo.EMPLOYEE_BILL_VCHR_CODE_ALLOCATIONS
where time_stamp >= @LastProcessedDate

実行計画で、推定行数と実際の行数の間に大きなギャップが見つかりました。したがって、週に2回統計を更新し、テーブルのすべての統計を再度更新して、同じSELECTステートメントを実行しました。

しかし、それは同じです。

こちらが実行計画です。

enter image description here

そして最後の統計更新日。

enter image description here

ありがとう

2
Rajesh Ranjan

他の人が指摘したように、最も差し迫った問題はローカル変数の使用です。 SQL Serverは、ローカル変数に値を割り当てる前に、そのクエリのクエリプランを作成します。 _>=_演算子を使用してフィルタリングされた不明な入力があります。 SQL Serverの従来のカーディナリティエスティメータには、これを特殊なケースとして扱うルールがあります。カーディナリティの推定値は、常に、フィルター列にnull以外の値を持つテーブルの行数の30%になります。

私はあなたが持っている多くのNULL値を知りませんが、あなたが数学をすればそれはほとんど正確にうまくいきます:

27451373 * 0.3 = 8235411.9

この問題を回避する方法はいくつかあります。 OPTION (RECOMPILE)ヒントを使用できます。これにより、SQL Serverはキャッシュされたクエリプランを使用せず、変数が割り当てられた後にクエリプランを作成します。ほとんどの場合、プラン内の変数の実際の値が表示されます。未知の推定値である30%は使用されなくなります。 SQL Serverが知っている1つの例外は、RECOMPILEヒントを使用するクエリであっても、些細なクエリをパラメーター化する可能性があることです。その場合、プランに変数値が表示されない場合があります。このテーブルは、より大きなクエリの一部であると思います。もしそうなら、あなたはその問題を持つべきではありません。

他のオプションは、フィルター値をクエリにハードコードする、動的SQLを使用する、またはパラメーター化されたクエリを使用することです。私の好みはRECOMPILEヒントです。ただし、クエリを1日に何度も実行しない限り、プランを再コンパイルする余裕はありません。

また、推定される行数が実際の行数と完全に一致することは比較的まれであることも指摘しておきます。完全一致を取得するには、通常、単純なクエリを使用する必要があります。また、統計情報で幸運を得る必要があります。

3
Joe Obbish