このパーティションビューで無関係なテーブルをオプティマイザに強制的に削除させることはできますか?


22

私は大きなテーブルのさまざまなアーキテクチャをテストしていますが、私が見た提案の1つは、大きなテーブルを一連の小さな「パーティション」テーブルに分割するパーティションビューを使用することです。

1234

このアプローチをテストする中で、あまり意味をなさない何かを発見しました。ファクトビューの「パーティション列」でフィルタリングすると、オプティマイザーは関連するテーブルのみを検索します。さらに、ディメンションテーブルのその列でフィルタリングすると、オプティマイザーは不要なテーブルを削除します。

ただし、ディメンションの他の側面でフィルタリングすると、オプティマイザーは各ベーステーブルのPK / CIを検索します。

問題のクエリは次のとおりです。

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where o.ObservationDateKey >= 20000101
    and o.ObservationDateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.DateKey >= 20000101
    and od.DateKey <= 20051231
group by od.[Year];

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where od.[Year] >= 2000 and od.[Year] < 2006
group by od.[Year];

キーのファクトフィルター

キーの減光フィルター

アスペクトの減光フィルター

SQL Sentry Plan Explorerセッションへのリンクは次のとおりです。

私は実際に大きなテーブルをパーティション分割して、同様の方法で応答するパーティションを削除できるかどうかを確認しています。

ディメンションの側面でフィルター処理する(単純な)クエリのパーティション削除を取得します。

それまでの間、データベースの統計のみのコピーを次に示します。

https://gist.github.com/swasheck/9a22bf8a580995d3b2aa

「古い」カーディナリティ推定器は、より安価なプランを取得しますが、それは各(不要な)インデックスシークのカーディナリティ推定値が低いためです。

ディメンションの別の側面でフィルター処理するときにオプティマイザーがキー列を使用して、無関係なテーブルでのシークを排除できるようにする方法があるかどうかを知りたい。

SQL Serverバージョン:

Microsoft SQL Server 2014 - 12.0.2000.8 (X64) 
    Feb 20 2014 20:04:26 
    Copyright (c) Microsoft Corporation
    Developer Edition (64-bit) on Windows NT 6.3 <X64> (Build 9600: ) (Hypervisor)

ちょうどFYI ..最後のstatストリームが破損しているCREATE STATISTICS [_WA_Sys_00000008_2FCF1A8A] ON [dbo].[Observation_2010]([StationStateCode]) WITH STATS_STREAM = 0x01000000010000000000000000000000D4531EDB00000000D5080000000000009508000000000000AF030000AF000000020000000000000008D000340000000007000000E65DE0007DA5000076F9780000000000867704000000000000000000ABAAAA3C0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
キン・シャー

統計のみのデータベースのスクリプトは切り捨てられているようです。「ファイル全体を表示」をクリックしてzipをダウンロードしようとしましたが、いずれにしてもObservationDatesテーブルの統計情報がありません。4199であっても、ポールと同じ計画を立てていません。これが理由だと思います。
ジェフパターソン

@GeoffPattersonそれは私のために働く。生ファイルへのリンクをクリックしましたか?gist.githubusercontent.com/swasheck/9a22bf8a580995d3b2aa/raw / ... ただし、Kinが指摘したように、最後の統計ストリームが破損している:/
swasheck

生ファイルのリンクをクリックしました。スクリプトは動作します(Kinが指摘した問題を除く)が、統計を作成するためのロジックは含まれていませんObservationDatesUPDATE STATISTICS ObservationDates WITH ROWCOUNT = 10000しかし、ポールが示した計画を得るために、私は手動で実行することになりました。
ジェフパターソン

奇数。新しいデータベースを作成し、そのスクリプトを実行すると、統計オブジェクト(インデックスです)がありますObservationDatesので、何が起こっているのかわかりません。また、私は計画ポールを生成することもできません。更新を試してみます。
-swasheck

回答:


10

トレースフラグ4199を有効にします。

私も発行しなければなりませんでした:

UPDATE STATISTICS dbo.ObservationDates 
WITH ROWCOUNT = 73049;

以下に示す計画を取得します。このテーブルの統計はアップロードにありませんでした。73,049という数字は、プランエクスプローラーの添付ファイルのテーブルカーディナリティ情報から取得されました。SQL Server 2014 SP1 CU4(ビルド12.0.4436)を使用し、2つの論理プロセッサ、最大メモリを2048 MBに設定し、4199以外のトレースフラグを使用しませんでした。

その後、動的パーティションの削除を特徴とする実行計画を取得する必要があります。

select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
where 
    od.[Year] >= 2000 and od.[Year] < 2006
group by 
    od.[Year]
option (querytraceon 4199);

計画フラグメント:

計画フラグメント

これは悪く見えるかもしれませんが、フィルターはすべて起動フィルターです。述語の例は次のとおりです。

フィルターのプロパティ

ループの反復ごとに、起動述語がテストされ、それがtrueを返す場合のみ、その下のクラスター化インデックスシークが実行されます。したがって、動的パーティションの削除。

これはおそらくではありません、かなり計画が平行になっている場合は特に、除電ほど効率的。

あなたのようなヒントを試してみる必要があるかもしれないMAXDOP 1FAST 1またはFORCESEEKビューに同じプランを取得します。(パーティション表のように)分割ビューでの選択肢の原価計算オプティマイザ注意が必要です。

ポイントは、機能が起動することをフィルタを分割ビューの動的なパーティションの除去を取得する計画が必要です。


埋め込まれたとのクエリUSE PLANヒント:(gist.github.com経由):


1
ポール、ありがとう!回答を書いた後、なぜSQL Serverがこの種の除去を行うことができないのか疑問に思っていました。そこにあることが判明しました、私は前にそれを見たことがありませんでした!
ジェフパターソン

6

私の観察では、パーティションビューで "テーブルの削除"を行うには、クエリでパーティション列の値(または値の範囲)を明示的に指定する必要があります。これは、SQL Server 2000からSQL Server 2014までの運用環境でパーティションビューを使用した経験に基づいています。

SQL Serverには、ループの外側の行の値に基づいて、エンジンがループの内側の適切なテーブルに直接シークを直接向けることができるループ結合演算子の概念がありません。ただし、Paulの答えが説明しているように、ループの内側の無関係なテーブルを一定時間で動的にスキップするためのスタートアップフィルターを使用する計画の可能性があります(実際にシークを実行することによる対数とは対照的です)。

パーティションテーブルに対して、しかし、(特定のパーティションに)シークのこのタイプがサポートされていることに留意されたいです。

あなたがパーティションビューを使用して上に固定されている場合は、別のオプションは、次のような複数のクエリ、にあなたのクエリを分割することです:

-- Gather than the min/max values for the partition column
DECLARE @minDateKey INT,
        @maxDateKey INT
SELECT @minDateKey = MIN(DateKey),
        @maxDateKey = MAX(DateKey)
FROM dbo.ObservationDates od
WHERE od.[Year] >= 2000 and od.[Year] < 2006

-- Since I have a stats-only copy of the database, simulate having run the query above
-- (You can comment this out since you have the actual data.)
SELECT @minDateKey = 20000101, @maxDateKey = 20051231

-- Adjust the query to use the min/max values of the partition column
-- rather than filtering on a different column in the dimension table
select 
    od.[Year], 
    AvgValue = avg(ObservationValue)
from dbo.v_Observation o 
join dbo.ObservationDates od
    on o.ObservationDateKey = od.DateKey
WHERE od.DateKey >= @minDateKey AND od.DateKey <= @maxDateKey
group by od.[Year]
-- Must use OPTION RECOMPILE; otherwise the plan will touch all tables because it
-- must do so in order to be valid for all values of the parameters!
OPTION (RECOMPILE)

これにより、次の計画が得られます。ディメンションテーブルにヒットする追加のクエリがありますが、(おそらくはるかに大きい)ファクトテーブルに対するクエリは最適化されています。

ここに画像の説明を入力してください


変数に頼らずに最初のクエリを2番目のクエリに組み込んだ場合、同じ効果が得られますか?
アンドリーM

@AndriyM正しく理解している場合、答えは「いいえ」です。2つのクエリを結合しようとすると、同じ効果は得られず、クエリプランはパーティションビュー内のすべてのテーブルに影響します。最初のクエリを実行し、変数の代わりに値20000101を貼り付ける20051231(または、アプリケーションで2つの個別のクエリを介して同様の操作を行う)場合、はい、変数を使用せずに同じ効果が得られます。
ジェフ・パターソン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.