web-dev-qa-db-ja.com

SQL Serverで「ディメンションテーブルのパーティション分割を避ける」必要があるのはなぜですか?

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インデックス
  • 5/8 non-clusteredパーティションスキームのインデックス
  • 3/8 non-clusteredprimaryのインデックス、rows_filegroup
    • これらの1つはunique, non-clusteredインデックスでした(完全を期すために、ソース管理のテーブル作成スクリプトでprimary key non-clusteredとして定義されています)。

別のアップデート

Remus Rusanu によるこの回答が見つかりました。これは、ディメンションに関連するパーティションテーブルの複雑さを明らかにします。

彼の声明は上記の私の例を使用して私の解釈でブロック引用されています


非整列インデックスは、効率的なパーティション切り替え操作を妨げます

したがって、テーブルがパーティション分割されている場合は、インデックスを整列させる必要があります。アライメントされていないインデックスがあるため、パーティションの切り替えは、私の例ではテーブルをロードするために使用されていません(?.

アラインメントされたインデックスを使用すると、これらの問題は解決しますが、この物理的なストレージ設計のオプションがデータモデルに波及するため、独自の一連の問題が発生します。

これは確かに、私が提供した例の場合に当てはまるように思われ、アラインされたインデックスを実装するためにいくつかの変更が必要になります。

ディメンションは通常、代理キーをprimary key(a unique clustered index)として使用するため、増加する狭いキーを提供します(ディスク上のデータサイズが小さいなど)。ディメンションとファクト間の結合がより速く発生する可能性がある場合に発生するBツリーシークが発生するため、これは重要です。さらに、clustered indexは、作成されたnon-clustered indexesの一部になるため、非クラスター化インデックスの肥大化を防ぎ、より効率的なインデックスシーク/スキャンもここで作成します。

なぜこれが重要なのですか?

アラインされたインデックスは、一意の制約を作成/適用できなくなることを意味します(パーティション列を除く)

そして

分割テーブルを参照するすべての外部キーには、分割キーが含まれている必要があります

そして

次に、外部キー制約を適切に宣言するために、パーティションテーブルを参照するすべてのテーブルにパーティションキー列の値...が含まれている必要があります。

影響は...

  • DateEffective列を、環境内の勘定ディメンションを参照するeveryテーブルに追加する必要があります。このルックアップは、正しいDateEffectiveキー値をロードするETLプロセスによって処理されるため、ファクトテーブルにAccountID列を実装することは冗長です。さらに、一部のファクトはdateデータ型よりも選択的である粒度で宣言されており、DateEffectiveは明らかにそのため、この列をファクトテーブル(データモデル波及効果)。
  • DateEffective列を含めるには、いくつかのnon-clustered indexesを変更する必要があります

ただし...

  • 通常、データウェアハウスにはforeign key制約が実装されていません。 SOはこれをカバーしています
  • また、2008年以降、Sql Serverはparallel bitmap filtered hash-joinsを使用してスター型結合を最適化でき( ビットマップフィルタリングによるデータウェアハウスクエリパフォーマンスの最適化 を参照)、外部キーは不要です。この最適化のため。
  • これは、seemを指し、ディメンションテーブルをパーティション分割しても問題ないことを示します。現在、外部キー制約の問題は私たちの環境には存在しないため、パーティションキーを非整列インデックスに含める必要があるのは「唯一」です(ETLプロセスがこの整合性を管理します)。
5
Adrian Torrie

アドバイスは、ディメンションテーブルをパーティション分割することによるユーティリティの可能性に基づいていると思います。データウェアハウスでは、ファクトテーブルが格言の良い例です(ビッグデータは中程度のデータであり、時間です)。ディメンションテーブルには時間がありません(実際にはありません)。また、原則として、有用なパーティションプロパティはありません。

あなたのものは良い例のようです。 AccountsDateEffectivepartitionedとなるのはなぜですか? 「一部のレポートはその列を選択しているため」では十分な回答ではありません。その列のインデックスは従来のソリューションであり、物理データ構造にバイアスをかけないという利点があります。

アカウントの数に関係なく、ファクトテーブルは少なくとも1〜3桁大きくなります。サーバーはその比率にスケーリングされます。アカウントの検索は比較的簡単な操作です。一見すると、パーティション分割の候補のようには見えません。

1
James K. Lowden