データベースを開発する場合、多くの場合、オブジェクトのバージョン管理と履歴の保存をサポートする必要があります。 たとえば、従業員が職位を変更し、職位が給与を変更する場合があります-多次元モデリングでは、これは緩やかに変化するディメンション(以下、SCD)と呼ばれます-ほとんど変化しないディメンション、つまり非キー属性が時間とともに変化する傾向があるディメンション 合計で、
SCDには6つの基本タイプ(メソッド)があり、これらは変更履歴をモデルに反映する方法を決定します。
タイプ0
これは、テーブルで最初にヒットした後のデータがそれ以上変更されないという事実にあります。 この方法は、実際には誰も使用していません。 バージョニングはサポートしていません。 SCD方法論のゼロ基準点としてのみ必要です。
タイプ1
タイプ1は、古いデータを新しいデータに書き換える通常の方法です。 純粋な形式では、このメソッドはバージョン管理も含まず、ストーリーが実際に必要でない場合にのみ使用されます。 ただし、このタイプの一部のDBMSでは、DBMS自体(Oracleのフラッシュバッククエリなど)を使用するか、トリガーを介して変更を追跡することで、制限付きのバージョン管理サポートを追加できます。
利点:
短所:
タイプ2
この方法では、バージョンごとに、このバージョンのキー属性フィールドが追加されたテーブルに個別のレコードを作成します。たとえば、バージョン番号、変更日、バージョンの存在期間の開始日と終了日です。
例:
ID | NAME | POSITION_ID | DEPT | DATE_START | DATE_END |
---|
1 | コリャ | 21 | 2 | 08/11/2010 10:42:25 | 9999年1月1日 |
2 | デニス | 23 | 3 | 08/11/2010 10:42:25 | 9999年1月1日 |
3 | ボリス | 26 | 2 | 08/11/2010 10:42:25 | 9999年1月1日 |
4 | シェルドン | 22 | 3 | 08/11/2010 10:42:25 | 9999年1月1日 |
5 | ペニー | 25 | 2 | 08/11/2010 10:42:25 | 9999年1月1日 |
この例では、デフォルトのバージョン日付は'01 .01.9999 'であり、その代わりに、たとえばnullを指定することは可能ですが、ID、DATE_STARTおよびDATE_ENDから主キーを作成することに問題があり、さらに、特定の日付の選択条件が簡素化されます(「
where snapshot_date>DATE_START and (snapshot_date < DATE_END or DATE_END is null)
」の代わりに「
where snapshot_date>DATE_START and (snapshot_date < DATE_END or DATE_END is null)
where snapshot_date between DATE_START and DATE_END
」」。
この実装では、従業員を解雇するときに、従業員のレコードを削除する代わりに、現在のバージョンの終了日を解雇の日付に変更するだけで済みます。
利点:
- 完全かつ無制限のバージョン履歴を保持します
- 必要な期間のデータへの便利で簡単なアクセス
短所:
- 冗長性の誘発、または可変ディメンション属性を格納するための追加テーブルの確立
- 分析がファクトテーブルのデータを特定のバージョンのディメンションと調整する必要があり、ファクトがこのファクトのディメンションの現在のバージョンと一致しない場合、構造が複雑になるか冗長性が追加されます(たとえば、クライアントのリビジョンまたは住所が変更されたが、古い値による操作/配信)
タイプ3
レコード自体には、以前の属性値の追加フィールドが含まれています。 新しいデータを受信すると、古いデータは現在の値で上書きされます。
| ID | UPDATE_TIME | LAST_STATE | CURRENT_STATE |
---|
1 | 1 | 08/11/2010 12:58:48 | 0 | 1 |
2 | 2 | 08/11/2010 12:29:16 | 1 | 1 |
利点:
短所:
タイプ4
変更の履歴は別のテーブルに含まれます。メインテーブルは常に、現在のデータで上書きされ、古いデータが別のテーブルに転送されます。 通常、このタイプは変更の監査またはアーカイブテーブルの作成に使用されます(Oracleで、フラッシュバックアーカイブを使用して1番目から同じ4番目のタイプを取得できます)。 私のように、このオプションのサブタイプまたはハイブリッド(2番目のタイプ)は、許容される行の移動を伴う現在のバージョンに基づいてパーティション化することを検討する必要がありますが、これはすでにモデリングの範囲を超えており、おそらく管理に関連しています。
例:
select * from emp
ID | NAME | POSITION_ID | DEPT |
---|
1 | コリャ | 21 | 2 |
2 | デニス | 23 | 3 |
3 | ボリス | 26 | 2 |
4 | シェルドン | 22 | 3 |
5 | ペニー | 25 | 2 |
select * from emp_history
ID | NAME | POSITION_ID | DEPT | DATE |
---|
1 | コリャ | 21 | 1 | 11/11/2010 14:12:13 |
2 | デニス | 23 | 2 | 11/11/2010 14:12:13 |
3 | ボリス | 26 | 1 | 11/11/2010 14:12:13 |
4 | シェルドン | 22 | 2 | 11/11/2010 14:12:13 |
利点:
短所:
ハイブリッドタイプ/タイプ6(1 + 2 + 3)
タイプ6は、上記の方法の組み合わせとして
Ralph Kimballによって発明されたもので、考慮していない状況やデータを扱う便利さのために設計されています。 それは追加の冗長性を導入することから成ります:タイプ2が基礎として採用され、代替属性が代替バージョンの概要(タイプ3)に追加され、1つまたはすべての以前のバージョン(タイプ1)が上書きされます。
例:
バージョン | ID | NAME | POSITION_ID | DEPT | DATE_START | DATE_END | 現在の |
---|
1 | 1 | コリャ | 21 | 2 | 08/11/2010 10:42:25 | 9999年1月1日 | 1 |
1 | 2 | デニス | 23 | 3 | 08/11/2010 10:42:25 | 9999年1月1日 | 1 |
1 | 3 | ボリス | 26 | 2 | 08/11/2010 10:42:25 | 08/11/2010 11:42:25 | 0 |
2 | 3 | ボリス | 26 | 2 | 08/11/2010 11:42:26 | 9999年1月1日 | 1 |
この例では、たとえば、サロゲートキーを追加すると、ファクトテーブルからディメンションの特定のバージョンを参照する機能が追加されます。これは、ファクト自体の時間に属さない場合があります。レコード自体を変更せずにバージョンが古くなる可能性があるため)。 ただし、現在のバージョンのインジケーターは、テーブルで必要な場合(DBMSがそのようなフィールドをサポートしている場合、バージョン11でOracleに表示された場合)、正規化を損なうことなく仮想の計算可能なフィールドとして、またこのテーブルからのビューのフィールドとして作成できます
一般に、SCDの主要なタイプの組み合わせはハイブリッドタイプを指すため、欠点と利点は特定の実装に依存しますが、1つ確かなことはあります-ハイブリッドタイプの選択は、モデルの複雑さによってのみ決定でき、ほとんどの場合(私はしませんそれ以外の場合)、主な4つのタイプで実行できます。
SCDの実装に関するヒントをいくつか追加します。
- ストアドプロシージャのレコードを変更するためのメカニズムを実装してみてください。変更コードが外部アプリケーションの明確に定義された場所に保存されている場合でも、変更コードが異なる場所に散在することはまったく望ましくありません。
- 1番目のモデルから2番目のモデルにスムーズに移行したい場合、これを行うことができます。
1)たとえば、table_name_scd2に名前を変更して、タイプ2 SCDでテーブルを変更します。
2)古いテーブルの名前で更新されたビューを作成します。これにより、古いテーブルと同じ構造のデータが生成されます。
3)ストアドプロシージャですべての変更を行わない場合(これが一時的なことを望みます:))、既に変更されている場合は、新しいフィールドがリクエストによって設定されていない場合(new.start_dateがnullの場合)に入力するトリガーを作成します..)そして、すべてを変更したことを確認するためにログに記録します - バージョンの開始フィールドと終了フィールドを使用する場合、オブジェクトの識別子とバージョンの開始日と終了日を含む主キーを使用することに加えて、バージョン日付の非交差に制限を作成することで整合性を制御する必要があります。 DBMSがこれを行うことができる非決定的関数に基づいたチェック制約をサポートしている場合は非常に良いです(ちなみに、どのDBMSがこれをサポートしているか知りたいのですが)、そうでない場合は、トリガーを作成または変更する前に条件をチェックして、例外をスローできます違反の場合。 Oracleの例:
create or replace trigger T_EMP_CHECK before insert or update on emp for each row declare f_ok number; begin select count(*) into f_ok from dual where exists( select null from emp e where e.id = :new.id and e.date_start <= :new.date_end and e.date_end >= :new.date_start ); if f_ok>0 then raise DUP_VAL_ON_INDEX; end if; end T_EMP_CHECK;
- タイプ1からタイプ4に切り替える場合、更新前トリガーを作成するだけで、アーカイブレコード用の新しいテーブルにレコードを保存できます。
PS。 Habralyudi、あなたが出会った興味深いハイブリッド実装を教えてください。