web-dev-qa-db-ja.com

追加のフィルタリングされた統計が無視されるのはなぜですか(EAVスキーマ)?

このサブクエリ(より大きなクエリの)の行の見積もりを改善しようとしています。見積もりは1266行を示しています。実際は117k行です。この特定のプロパティ(EAVスキーマ)には、2つの値(2と3)のみが定義されています。

declare @pPropVal smallint = 2;

select Value, ObjectId 
  from Oav.ValueArray PropName
 where PropName.PropertyId = 897
   and PropName.Value  = @pPropVal
option (recompile)

クエリプランは、期待どおり、PropertyIdおよびValueのインデックスIX_ValueArray_PropValObjに適切なシーク述語を示しています。

[〜#〜] a [〜#〜])行の見積もりを改善する試みとして、追加の統計が追加され、行の見積もりがわずかに3041になりました。

create statistics [ST_SomePropertyName] ON [Oav].[ValueArray](PropertyId, Value, ObjectId)
 where 
     (     
             PropertyId = 897 
         and [Value] is not null
     )
  with fullscan

ヒストグラムは単一の行を示しています。 HIキーはPropertyId(最初の列)であり、私が理解しているようにそれほど有用ではないため、密度情報を使用しています。

RANGE_HI_KEY    RANGE_ROWS  EQ_ROWS  DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
897             0           196026   0                    1

All density Average Length  Columns
1           4               PropertyId
0.5         8               PropertyId, Value

Name    Updated Rows    Rows Sampled    Steps   Density Average key length  String Index    Filter Expression   Unfiltered Rows
ST_SomePropertyName May 20 2014  2:01PM 196026  196026  1   0   8   NO  ([PropertyId]=(897) AND [Value] IS NOT NULL)    9317055

[〜#〜] b [〜#〜])PropertyId = 897にフィルターがあるので、次のような統計を再作成できると思いました。

create statistics [ST_SomePropertyName] ON [Oav].[ValueArray](Value, ObjectId)
where
    (       
       PropertyId = 897 
       and [Value] is not null
    )
 with fullscan

ヒストグラムは私の目には便利に見えますが、元の推定値である1266に戻るため、推定器はそれを無視しているように見えます。

RANGE_HI_KEY  RANGE_ROWS  EQ_ROWS  DISTINCT_RANGE_ROWS   AVG_RANGE_ROWS
2             0           117760   0                     1
3             0           78266    0                     1

All density   Average Length  Columns
0.5           4               Value
5.101364E-06  12              Value, ObjectId

Name    Updated Rows    Rows Sampled    Steps   Density Average key length  String Index    Filter Expression   Unfiltered Rows
ST_SomePropertyName May 20 2014  2:04PM 196026  196026  2   0   12  NO  ([PropertyId]=(897) AND [Value] IS NOT NULL)    9317055

[〜#〜] c [〜#〜])固定値にフィルタリングすることはできますが(2番目の2列も必要ありません)、それはあまり実用的な解決策ではありません。これにより、正確な見積もりは117kになりました。

create statistics [ST_SomePropertyName] ON [Oav].[ValueArray](PropertyId)
 where 
     (     
             PropertyId = 897 
         and [Value] = 2
     )
  with fullscan

ヒストグラム:

RANGE_HI_KEY   RANGE_ROWS  EQ_ROWS  DISTINCT_RANGE_ROWS  AVG_RANGE_ROWS
897            0           117760   0                    1

[〜#〜] d [〜#〜])(元の質問に追加)値をより小さな範囲に制限するアプローチが役立ちます。ただし、範囲の値が均一でない場合、値が文字列ベースのフィールドである場合、または不明な場合でも、これは一般的に適切な回避策ではない可能性があります。

CREATE STATISTICS [ST_ListUnderBrand_897] ON [Oav].[ValueArray](PropertyId, Value)
WHERE 
  (       
      PropertyId = 897 
      and [Value] >= 1 and [Value] <= 20
  )
  with fullscan

これにより、約16kの見積もりが得られます。 [1,20]を正確な[2,3]に変更すると、約80kの見積もりが得られます。テーブルデータの値の実際の範囲は実際には使用されていないことは明らかであり(2列目であるため)、これは主にフィルター範囲に基づく推定値です。

[値]フィールドはsql_variantですが、クエリプランには暗黙的な変換が表示されないため、これは関連していないことに注意してください。

SQL ServerがBの統計を使用しないのはなぜですか?それをすべきですか?

これを修正するために利用できる他のオプションはありますか?

6
crokusek

OPTION (RECOMPILE)クエリヒントを使用し、SQL Server 2008 R2以降を実行していない限り、ローカル変数を使用している場合、フィルター処理されたインデックスと統計は機能しません。

Tim ChapmanのMSDNブログ投稿で例を挙げて説明しています。

6
Brent Ozar