web-dev-qa-db-ja.com

統計は最新ですが、見積もりが正しくありません

dbcc show_statistics ('Reports_Documents', PK_Reports_Documents)を実行すると、レポートID 18698に対して次の結果が得られます。

enter image description here

このクエリの場合:

_SELECT * 
FROM Reports_Documents 
WHERE ReportID = 18698 option (recompile)
_

クラスター化インデックスを_PK_Reports_Documents_で期待どおりにシークさせるクエリプランを取得します。

しかし、私を困惑させるのは、推定行数の誤った値です。

enter image description here

this によると:

サンプルクエリのWHERE句の値がヒストグラムのRANGE_HI_KEYの値と等しい場合、SQL ServerはヒストグラムのEQ_ROWS列を使用して、等しい行の数を決定します

これは私が期待する方法でもありますが、実際にはそうではないようです。また、_RANGE_HI_KEY_によって提供されるヒストグラムに存在する他の_show_statistics_値をいくつか試し、同じことを経験しました。私の場合、この問題により、一部のクエリで最適化されていない実行プランが使用され、実行時間は数分になるようですが、クエリヒントを使用すると1秒で実行できます。

全体として:ヒストグラムの_EQ_ROWS_が推定行数に使用されない理由と、誤った推定がどこから来たのか、誰かが私に説明できますか?

もう少し(おそらく役立つ)情報:

  • 統計の自動作成がオンになっており、すべての統計が最新です。
  • クエリ対象のテーブルには約8000万行あります。
  • _PK_Reports_Documents_は、_ReportID INT_とDocumentID CHAR(8)で構成されるPKの組み合わせです。

クエリは、合計5つの異なる統計オブジェクトをロードしているようです。これらのオブジェクトにはすべて、ReportID +テーブルのいくつかの他の列が含まれています。それらはすべて新しく更新されました。以下の表の_RANGE_HI_KEY_は、ヒストグラムの最高の上限列値です。

_+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
|                                  name                                   | stats_id | auto_created | user_created | Leading column Type | RANGE_HI_KEY | RANGE_ROWS | EQ_ROWS  | DISTINCT_RANGE_ROWS | AVG_RANGE_ROWS |
+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
| PK_Reports_Documents                                                    |        1 |            0 |            0 | Stationary          |        18722 | 0          | 2228,526 |                   0 | 1              |
| _dta_index_Reports_Documents_42_1629248859__K1_K63_K14_K13_K22_K23_72_6 |       62 |            0 |            0 | Stationary          |        18698 | 0          | 2228,526 |                   0 | 1              |
| _dta_stat_1629248859_1_1_59                                             |       76 |            0 |            1 | Stationary          |        18686 | 50,56393   | 1        |                   0 | 13397,04       |
| _dta_stat_1629248859_1_22_14_18_12_6                                    |       95 |            0 |            1 | Stationary          |        18698 | 0          | 2228,526 |                   0 | 1              |
| _dta_stat_1629248859_1_7_14_4_23_62                                     |       96 |            0 |            1 | Stationary          |        18698 | 56,63327   | 21641,5  |                   0 | 14526,44       |
+-------------------------------------------------------------------------+----------+--------------+--------------+---------------------+--------------+------------+----------+---------------------+----------------+
_

_sp_updatestats_は、統計を更新するために毎晩実行するようにスケジュールされています。

12
user1151923

これには簡単な解決策があります:

すべての_dta_...統計情報を取得し、DTAの推奨事項を盲目的に適用するのをやめます。

詳細

特定の問題は、問題の列に複数の統計セットがあったことです。追加のdta統計は、データのサンプリングによって作成されました(インデックスに関連付けられていない統計のデフォルトの動作)。

サンプリングされた統計の場合によくあることですが、結果のヒストグラムは基礎となるデータの全範囲をカバーしていませんでした。問題のクエリは、たまたまヒストグラムの外の値を選択したため、1行の推定値が得られました。

同じ列に統計の複数のセットが存在する場合のクエリオプティマイザーの正確な動作は、完全に文書化されていません。サンプリングよりも「フルスキャン」統計を優先する傾向がありますが、古い統計よりも最近更新された統計を優先します。

10
Aaron Bertrand