履歴/テンポラルテーブルのベストプラクティス


11

履歴を追跡したい特定のフィールドと、履歴を追跡したくない特定のフィールドを持つオブジェクトがあるとします。正規化の観点からは、次のスキーマで問題ありません。

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

ここで、MyObjectHistoryには、最新のリビジョンを除くすべての追跡フィールドが含まれています。または、次のように、追跡されるすべてのフィールドが1つのテーブルにあり、最新のものを含むすべてのリビジョンがそのテーブルにある必要があります。

CREATE TABLE MyObject AS (
    MyObjectId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectField1 VARCHAR(100) NOT NULL,
    MyObjectField2 VARCHAR(100) NOT NULL,
    MyObjectField3 VARCHAR(100) NOT NULL,
)
CREATE TABLE MyObjectHistory AS (
    MyObjectHistoryId INT IDENTITY NOT NULL PRIMARY KEY,
    MyObjectId INT NOT NULL FOREIGN KEY REFERENCES MyObject(MyObjectId),
    MyObjectTrackedField1 VARCHAR(100) NOT NULL,
    MyObjectTrackedField2 VARCHAR(100) NOT NULL,
    MyObjectTrackedField3 VARCHAR(100) NOT NULL,
)

私は@Joelに同意します
HaBo

回答:


7

実際のデータアクセスの理由から、最初のオプションの構造を使用する必要がありますが、履歴テーブルの現在のバージョンを含む追跡された列の値のすべてのバージョンを保持してください。

これは、一般に、履歴を確認する場合に、現在のバージョンと過去のすべてのバージョンを含める必要があるためです。歴史を見たくないときは、邪魔にならないようにしたいでしょう。多くの場合、これは履歴を個別のスキーマまたはデータベースに完全に分離することを意味します。履歴を現在のデータと同じスキーマで保持している場合でも、履歴データ(現在の値を含む)を参照するクエリは、2つのソースを基本的に結合する必要があるため、はるかに複雑になります。


2

おそらく履歴を表示する必要はほとんどないが、現在の値を頻繁に表示する必要があるため、最初のバージョンを選択します。履歴テーブルにはトリガーからデータを入力する必要があるため、一般的にデータが同期されなくなることを心配する必要はありません。MyObjectに100万のレコードがあり、MyObjectHistoryに10,000,000のレコードがあるとします。現在の値を取得するために、それだけ多くのレコードを持つテーブルに本当に結合しますか?

現在の値よりも頻繁に、またはそれ以上の頻度で履歴を照会する必要がある場合は、2番目の構造が機能します。(そして、特定の日付の値を表示する場合は、クエリをより簡単にするためにbegindateフィールドとenddateフィールドをそこに含めます。)

ところで、変更が発生した順序がわかるように、履歴テーブルに日付フィールドを追加します。時系列でのIDに依存することはできません。PLus previosu値について質問がある場合、値が変更されたときは、知っておく必要があります。変更元のアプリケーション(複数のアプリケーションがある場合)および/または変更を行った人の値も入力する場合があります。


0

#1には2つの重要な理由があります。1つ目は、HLGEMが指摘するサイズの問題ですが、他にも重要な問題があります。

通常、監査証跡では、時間の経過とともに要件が作成されます。最終的に、データベースユーザー、変更の時間などを追跡する必要がある場合があります。監査証跡の要件とメインテーブルは、時間の経過とともに多少独立して変更される可能性があります。最後に、一定期間後に監査証跡データを個別にパージし、完全に別のテーブルを削除することもできます。

もちろん、履歴データは現在の計算に使用される可能性があり、レコードの数は比較的少ないため、それらを完全にマージしたい場合があります(LedgerSMBの税率の場合と同様)。

ただし、このようなテーブルにオブジェクトを格納しても、優れた正規化されたデザインが得られることはめったにありません。私の経験では、正規化された適切なストレージとアプリケーションオブジェクトモデルの間のカプセル化が本当に必要です。


2
「適切な正規化ストレージとアプリケーションオブジェクトモデル間のカプセル化」とはどういう意味ですか?このアイデアについて説明したり、例を挙げたりしますか?
cubetwo1729 2013
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.