現在、次のクエリ例を実行しようとしています。
_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で実行すると、次のクエリプランが表示されます。
ここでは、探しているレコードの数を大幅に過大評価しています。これが、実行が非常に遅い理由であると私は信じています。
統計を更新しましたが、それは問題ではなかったので、クエリの問題のままです。
また、次を使用してSQLを強制的に並列実行することにより、クエリの速度を向上させることができました。
_OPTION(QUERYTRACEON 8649)
_
これにより、次の実行プランが作成されます。
これは高速ですが、それでも行数を過大評価しています。
なぜこの見積もりが非常に高いのか、そしてどうすればそれを減らすことができるのかを誰かが理解してくれることを期待していました。
クラスター化されたインデックスの定義:
_/****** 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
私の見方-問題はSQLが悪いこと、ひどく悪いことです。
で始まる:
[DIMENSION3] IN(48)AND
要素が1つある場合は、INではなくWhereを生成します。
しかし、さらに悪いことに:
[DIMENSION10] IN(1、235、...(おそらく数千の数))AND
INに関する統計はないため、小さい選択で最適に機能します。この場合、統計付きの一時テーブルを作成し、そこに値をロードしてから、INをある種の副選択に置き換えることをお勧めします。このようにして、クエリオプティマイザは実際に(選択性の観点から)自分が直面していることを認識し、別の方法でアプローチすることを決定する場合があります。
そうでなければあなたのために2つのことがあります;)
そのようなクエリは、SQLServerを実際に拡張します。それは進歩しましたが、これはまさにAnalysisServerキューブの目的です。
問題は統計の改善ではなく、問題のあるインデックス作成戦略にある可能性があります。
通常、すべて(または多数)の列にインデックスを付けることは効果的ではありません。インデックスは、小さなデータ型(int、bigints、small varchars)を使用して、少数の高カーディナリティ列から構築することを目的としていました。
挿入またはETLプロセスの一部として、varbinary(max)のような巨大な列をハッシュしてから、それらにインデックスを付けることを検討できます。
SQL Serverで多くの大きな列の一意性を処理する方法は?
メインテーブルの行数はいくつですか?それらの行の何パーセントがクエリによって返されますか?
クエリがデータの約20%を返す場合、NCインデックスをスキャンすると、スキャン中の異なる時間に同じデータページにアクセスしてそのページの複数の行を取得する可能性があるため、非クラスター化インデックスは検索パスとして削除される可能性があります。