web-dev-qa-db-ja.com

大規模な「WHEREIN」SQLServerクエリの統計を改善する

現在、次のクエリ例を実行しようとしています。

_SELECT [DATA1], [DATA2] FROM TABLE WHERE
    [DIMENSION0] IN (1, 5, ... (possibly 10s of numbers)) AND
    [DIMENSION1] IN (5) AND
    [DIMENSION2] IN (10) AND
    [DIMENSION3] IN (48) AND
    [DIMENSION4] IN (1) AND
    [DIMENSION5] IN (1) AND
    [DIMENSION6] IN (8) AND
    [DIMENSION7] IN (1) AND
    [DIMENSION8] IN (52) AND
    [DIMENSION9] IN (1, 10, ... (possibly 100s of numbers)) AND
    [DIMENSION10] IN (1, 235, ... (possibly 1000s of numbers)) AND
    [DIMENSION11] IN (1)
_

表は次のようになります。

D =寸法

_[D0] [D1] [D2] [D3] [D4] [D5] [D6] [D7] [D8] [D9] [D10] [D11] [DATA1] [DATA2]
_

これには、すべてのディメンションに沿ったクラスター化されたインデックスが含まれ、数百万のレコードが含まれる可能性があります。

このクエリをSSMSで実行すると、次のクエリプランが表示されます。

enter image description here

ここでは、探しているレコードの数を大幅に過大評価しています。これが、実行が非常に遅い理由であると私は信じています。

統計を更新しましたが、それは問題ではなかったので、クエリの問題のままです。

また、次を使用してSQLを強制的に並列実行することにより、クエリの速度を向上させることができました。

_OPTION(QUERYTRACEON 8649)
_

これにより、次の実行プランが作成されます。

enter image description here

これは高速ですが、それでも行数を過大評価しています。

なぜこの見積もりが非常に高いのか、そしてどうすればそれを減らすことができるのかを誰かが理解してくれることを期待していました。

クラスター化されたインデックスの定義:

_/****** Object:  Index [ClusteredIndex-20180726-083210]    Script Date: 
26/07/2018 09:47:58 ******/
CREATE UNIQUE CLUSTERED INDEX [ClusteredIndex-20180726-083210] ON 
[dbo].[TABLE]
(
[DIMENSION0] ASC,
[DIMENSION1] ASC,
[DIMENSION2] ASC,
[DIMENSION3] ASC,
[DIMENSION4] ASC,
[DIMENSION5] ASC,
[DIMENSION6] ASC,
[DIMENSION7] ASC,
[DIMENSION8] ASC,
[DIMENSION9] ASC,
[DIMENSION10] ASC,
[DIMENSION11] ASC,
)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, 
IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = 
ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
_

テーブルの挿入、更新、削除を行います。

Data2列はvarbinary(max)であるため、クラスター化列ストアインデックスを使用できません。非クラスター化バージョンを使用しようとしましたが、クエリプランはクラスター化インデックスを使用していました。

統計をFULLSCANで更新しました。他よりもヒットするディメンションがいくつかあります。以前、クラスター化インデックスのディメンションの順序を試しましたが、それでも行数を過大評価しています。

計画を含む完全なクエリ: https://www.brentozar.com/pastetheplan/?id=HyLHtXDVX

1
Andy

私の見方-問題はSQLが悪いこと、ひどく悪いことです。

で始まる:

[DIMENSION3] IN(48)AND

要素が1つある場合は、INではなくWhereを生成します。

しかし、さらに悪いことに:

[DIMENSION10] IN(1、235、...(おそらく数千の数))AND

INに関する統計はないため、小さい選択で最適に機能します。この場合、統計付きの一時テーブルを作成し、そこに値をロードしてから、INをある種の副選択に置き換えることをお勧めします。このようにして、クエリオプティマイザは実際に(選択性の観点から)自分が直面していることを認識し、別の方法でアプローチすることを決定する場合があります。

そうでなければあなたのために2つのことがあります;)

  • まともなハードウェアを入手してください;)それならおそらくメモリテーブルにありますか?
  • 分析サービスには理由があることを認識してください。

そのようなクエリは、SQLServerを実際に拡張します。それは進歩しましたが、これはまさにAnalysisServerキューブの目的です。

1
TomTom

問題は統計の改善ではなく、問題のあるインデックス作成戦略にある可能性があります。

通常、すべて(または多数)の列にインデックスを付けることは効果的ではありません。インデックスは、小さなデータ型(int、bigints、small varchars)を使用して、少数の高カーディナリティ列から構築することを目的としていました。

挿入またはETLプロセスの一部として、varbinary(max)のような巨大な列をハッシュしてから、それらにインデックスを付けることを検討できます。

SQL Serverで多くの大きな列の一意性を処理する方法は?

メインテーブルの行数はいくつですか?それらの行の何パーセントがクエリによって返されますか?

クエリがデータの約20%を返す場合、NCインデックスをスキャンすると、スキャン中の異なる時間に同じデータページにアクセスしてそのページの複数の行を取得する可能性があるため、非クラスター化インデックスは検索パスとして削除される可能性があります。

1
Victor Di Leo