SQL Catには、 大規模リレーショナルデータウェアハウスを構築するためのベストプラクティスのトップ10 というタイトルのヒントのリストがあります。
セクション4 - Design dimension tables appropriately
の下で、次のように述べています。
ディメンションテーブルのパーティション分割を避けます。
彼らはこれがなぜ行われるべきではないのかについて言及していませんし、ウェブ上でそれがなぜ回避されるべきなのかを明示的に指摘しているものも見つけられません。
ディメンションテーブルのパーティション分割を避ける必要があるのはなぜですか?
より具体的な例を以下に示し、回答を容易にし、大規模なリレーショナルデータウェアハウスでパーティショニングを行うべきではない理由について議論します。具体的な例に固有のデータモデルを改善するためのアドバイスは探していません。この例で、ディメンションの分割を行わない理由についての洞察が得られない場合は、無視してください。
私たちの環境にはAccount
ディメンションがあり、これはDateEffective
に分割されて読み込まれますmonthly。一部のクエリにはWHERE DateEffective >= @ReportDate
が含まれていますが、これはパーティションの削除に適した候補のようです。また、月のデータを再読み込みする必要がある場合は、月全体のデータを削除します。これも、テーブルのパーティション分割のメリットがあるようです。
質問を投稿してから、環境について更新します...
上記の表には、非整列の非クラスター化インデックスがあります( で調査される次のBrent Ozarコード )。
select
[db_name] = isnull(db_name(s.database_id),db_name())
,[schema_name] = object_schema_name(i.object_id,db_id())
,[object_name] = o.name
,index_name = i.name
,index_type_desc = i.type_desc
,data_space_name = ds.name
,data_space_type_desc = ds.type_desc
,s.user_seeks
,s.user_scans
,s.user_lookups
,s.user_updates
,s.last_user_seek
,s.last_user_update
from
sys.objects as o
inner join sys.indexes as i
on o.object_id = i.object_id
inner join sys.data_spaces as ds
on ds.data_space_id = i.data_space_id
left join sys.dm_db_index_usage_stats as s
on i.object_id = s.object_id
and i.index_id = s.index_id
and s.database_id = db_id()
where
o.type = 'u'
and i.type in (1, 2)
and o.object_id in
(
select filter.object_id
from
(
select ob.object_id, ds.type_desc
from
sys.objects ob
inner join sys.indexes ind on ind.object_id = ob.object_id
inner join sys.data_spaces ds on ds.data_space_id = ind.data_space_id
group by ob.object_id, ds.type_desc
) as filter
group by filter.object_id
having count(*) > 1
)
order by
[object_name] desc
;
clustered
インデックスnon-clustered
パーティションスキームのインデックスnon-clustered
primary
のインデックス、rows_filegroup
unique, non-clustered
インデックスでした(完全を期すために、ソース管理のテーブル作成スクリプトでprimary key non-clustered
として定義されています)。別のアップデート
Remus Rusanu によるこの回答が見つかりました。これは、ディメンションに関連するパーティションテーブルの複雑さを明らかにします。
彼の声明は上記の私の例を使用して私の解釈でブロック引用されています
非整列インデックスは、効率的なパーティション切り替え操作を妨げます
したがって、テーブルがパーティション分割されている場合は、インデックスを整列させる必要があります。アライメントされていないインデックスがあるため、パーティションの切り替えは、私の例ではテーブルをロードするために使用されていません(?.
アラインメントされたインデックスを使用すると、これらの問題は解決しますが、この物理的なストレージ設計のオプションがデータモデルに波及するため、独自の一連の問題が発生します。
これは確かに、私が提供した例の場合に当てはまるように思われ、アラインされたインデックスを実装するためにいくつかの変更が必要になります。
ディメンションは通常、代理キーをprimary key
(a unique clustered index
)として使用するため、増加する狭いキーを提供します(ディスク上のデータサイズが小さいなど)。ディメンションとファクト間の結合がより速く発生する可能性がある場合に発生するBツリーシークが発生するため、これは重要です。さらに、clustered index
は、作成されたnon-clustered index
esの一部になるため、非クラスター化インデックスの肥大化を防ぎ、より効率的なインデックスシーク/スキャンもここで作成します。
なぜこれが重要なのですか?
アラインされたインデックスは、一意の制約を作成/適用できなくなることを意味します(パーティション列を除く)
そして
分割テーブルを参照するすべての外部キーには、分割キーが含まれている必要があります
そして
次に、外部キー制約を適切に宣言するために、パーティションテーブルを参照するすべてのテーブルにパーティションキー列の値...が含まれている必要があります。
影響は...
DateEffective
列を、環境内の勘定ディメンションを参照するeveryテーブルに追加する必要があります。このルックアップは、正しいDateEffective
キー値をロードするETLプロセスによって処理されるため、ファクトテーブルにAccountID
列を実装することは冗長です。さらに、一部のファクトはdate
データ型よりも選択的である粒度で宣言されており、DateEffective
は明らかにそのため、この列をファクトテーブル(データモデル波及効果)。DateEffective
列を含めるには、いくつかのnon-clustered index
esを変更する必要がありますただし...
foreign key
制約が実装されていません。 SOはこれをカバーしています 。parallel bitmap filtered hash-joins
を使用してスター型結合を最適化でき( ビットマップフィルタリングによるデータウェアハウスクエリパフォーマンスの最適化 を参照)、外部キーは不要です。この最適化のため。アドバイスは、ディメンションテーブルをパーティション分割することによるユーティリティの可能性に基づいていると思います。データウェアハウスでは、ファクトテーブルが格言の良い例です(ビッグデータは中程度のデータであり、時間です)。ディメンションテーブルには時間がありません(実際にはありません)。また、原則として、有用なパーティションプロパティはありません。
あなたのものは良い例のようです。 Accounts
でDateEffective
partitionedとなるのはなぜですか? 「一部のレポートはその列を選択しているため」では十分な回答ではありません。その列のインデックスは従来のソリューションであり、物理データ構造にバイアスをかけないという利点があります。
アカウントの数に関係なく、ファクトテーブルは少なくとも1〜3桁大きくなります。サーバーはその比率にスケーリングされます。アカウントの検索は比較的簡単な操作です。一見すると、パーティション分割の候補のようには見えません。