低速変化ディメンション(SCD)は、データ 倉庫内の次元データへの変更を一定期間管理および追跡するためのフレームワークです。このフレームワークでは、データ SCD が低頻度で、時間枠に明確なパターンがない変更をカバーすることを想定しているため、次元を「低速」と参照します。データ倉庫の要件が、データの履歴状態に基づいて出力を追跡および複製する機能をカバーする場合は、SCD を使用します。
SCD の一般的ユースケースはレポート作成です。例、財務レポート システムでは、先月作成されたレポートの集計値とデータ 倉庫からの現在のバージョンのレポートの集計値との違いを説明する必要があります。
SQLにおける SCD のさまざまな実装は、「型」と呼ばれます。最も基本的な型である 0 型と 1 型は、それぞれデータの元の状態またはデータの現在の状態のみを追跡します。最も一般的に適用される実装である タイプ 2 では、validFrom
、validTo
、および最新のデータ セットに対する任意のフラグ(isValid
または isEffective
と呼ばれることが多い)の 3 つの新しいフィールドが作成されます。
SCD の種類
SCD タイプ | 説明 |
---|---|
タイプ 0 | 元の状態を維持するだけで、データは変更できません。 |
タイプ 1 | 更新された状態と履歴のみを保存することはできません。 |
タイプ 2 | 新しいドキュメントで履歴を保持します。 |
タイプ 3 | 同じドキュメント内の新しいフィールドに履歴を保持します。 |
タイプ 4 | 履歴を 別のコレクションに保持します。 |
タイプ 6 | タイプ 2 とタイプ 3 の組み合わせ。 |
MongoDBの SCD
SCDフレームワークは、 リレーショナルデータベースに適用するのと同じ方法でMongoDBに適用できます。徐々に変化していく次元の概念は、特定のユースケースに合わせて選択され最適化されたデータモデルのドキュメントごとに適用されます。
例
一連のアイテムの価格を保存する prices
というコレクションについて考えてみましょう。アイテムの返却を処理するには、時間の経過とともにアイテムの価格の変化を追跡する必要があります。返される金額は、購入時にアイテムの価格と一致する必要があるためです。コレクション内の各ドキュメントには item
と price
のフィールドがあります。
db.prices.insertMany( [ { 'item': 'shorts', 'price': 10 }, { 'item': 't-shirt', 'price': 2 }, { 'item': 'pants', 'price': 5 }, ] )
在庫の価格が 5
から 7
に変化するとします。この価格変化を追跡するには、 SCD タイプ 2 の必要なデータ フィールドにデフォルト値を想定します。validFrom
のデフォルト値は 01.01.1900
、validTo
は 01.01.9999
、isValid
は true
です。'item': 'pants'
を使用してオブジェクトの price
フィールドを変更するには、セットアップの現在の状態を表す新しいドキュメントを挿入し、以前は有効だったドキュメントを有効でなくなるように更新します。
let now = new Date(); db.prices.updateOne( { 'item': 'pants', "$or": [ { "isValid": false }, { "isValid": null } ] }, { "$set": { "validFrom": new Date("1900-01-01"), "validTo": now, "isValid": false } } ); db.prices.insertOne( { 'item': 'pants', 'price': 7, "validFrom": now, "validTo": new Date("9999-01-01"), "isValid": true } );
有効性の連鎖を中断しないようにするには、上記の両方のデータベース操作が同じタイムスタンプで発生するようにします。アプリケーションの要件に応じて、上記の 2 つのコマンドをトランザクションにラップして、 MongoDB が常に両方の変更を一緒に適用するようにできます。詳細については、トランザクションを参照してください。
次の操作は、pants
アイテムを含むドキュメントの最新の price
をクエリする方法を示しています。
db.prices.find( { 'item': 'pants', 'isValid': true } );
特定の点で pants
アイテムを含むドキュメントの price
をクエリするには、次の操作を使用します。
let time = new Date("2022-11-16T13:00:00"); db.prices.find( { 'item': 'pants', 'validFrom': { '$lte': time }, 'validTo': { '$gt': time } } );
いくつかのフィールドの変更の追跡
ドキュメント内のいくつかのフィールドの経時的な変更を追跡する必要がある場合は、フィールドの履歴を最初のドキュメントに配列として埋め込むことで、SCD タイプ 3 を使用できます。
例、次の集計パイプラインは、pants
を表すドキュメントの price
を 7
に更新し、前の price
が無効になったときのタイムスタンプ を持つ price
の以前の値を {という配列に保存します。 priceHistory
:
db.prices.aggregate( [ { $match: { 'item': 'pants' } }, { $addFields: { price: 7, priceHistory: { $concatArrays: [ { $ifNull: [ '$priceHistory', [] ] }, [ { price: "$price", time: now } ] ] } } }, { $merge: { into: "prices", on: "_id", whenMatched: "merge", whenNotMatched: "fail" } } ] )
配列サイズが大きくなりすぎると、このソリューションは遅くなったり非効率的になったりする可能性があります。大規模な配列を回避するには、 アウトバウンド パターンまたは バケット パターンを使用してスキーマを設計 できます。
Atlas Data Federation
上記の例では、ドキュメントフィールドの変更の厳密かつ正確な表現に焦点を当てています。場合によっては、履歴データの表示に関する要件がそれほど厳しくない場合があります。例、ほとんどの場合、データの現在の状態にアクセスするだけで必要なアプリケーションがあるとしますが、データの完全な履歴に対していくつかの分析クエリを実行する必要があります。
この場合は、データの現在のバージョンを 1 つのコレクションに、履歴変更を別のコレクションに保存できます。次に、MongoDB Atlasフェデレーティッドデータベース 機能を使用し、フルマネージド バージョンで Online アーカイブ を使用して、アクティブなMongoDBクラスターから履歴コレクションを削除できます。
その他のユースケース
次元を徐々に変化させることはデータを認識するのに役立ちますが、イベント駆動型アプリケーションで SCDフレームワークを使用することもできます。さまざまなタイプのイベントが頻繁にある場合、現在の状態を見つけるためにデータをグループ化またはソートする必要がある場合があるため、カテゴリごとに最新のイベントを見つけるのはコストがかかります。
頻度の低いイベントの場合は、ドキュメントあたりのイベント時間 に加えて、次のイベントの時間を保存するためのフィールドを追加してデータモデルを変更します。新しい日付フィールドにより、特定の点の検索を実行すると、検索しているそれぞれのイベントを簡単かつ効率的に検索できるようになります。