データベース内のデータのバージョン管理に関するSO(- this one など)に関するいくつかの質問を読みました。
言及された提案のいくつかが気に入りました。私は最も長い間、自分のテーブルの多くを修正する必要がありました(必要でした)が、それに取り掛かることはありませんでした。単純なデータベース作業だけを担当するプログラマーである私は、実際にこれを行うにはどうしたらよいのかと思っていました。
SQL構文での実際の解決策は求めていません。私は最終的に自分でそれを理解することができます(またはSO時が来たら投稿します)。私は、人々にどのようにそれを行うか、そしてそこで起こり得るパフォーマンスの問題についてコメントするように求めています何億件ものレコードを「改訂」することになったかもしれませんが、以下の例に基づいている限り、他の提案も可能です。
簡単な例を考えます:
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
UserID UINT NOT NULL, -- Who
TableName VARCHAR(50) NOT NULL, -- What
OldRecID UINT NOT NULL, -- Where
NewRecID UINT NOT NULL,
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
TableNameが文字列の場合、Auditテーブルを他のテーブル(Personなど)にリンクする方法がわかりません。
また、入力するGUIが3つあると仮定します。
1と2を実行するには、PersonテーブルまたはAuditテーブルをクエリする方が良いでしょうか?
3を達成するには、いわゆるデータベースエキスパートがすべてのレコードを取得してソフトウェアに渡し、処理するか、PersonIDと影響を受ける日付でグループ化するのでしょうか。これは通常、1つのクエリで処理されますか、それとも複数のクエリで処理されますか?
私は長年にわたってさまざまな監査スキームを行ってきましたが、現在は次のようなものを実装する予定です。
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
Person_History
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL
AuditID UINT NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
UserID UINT NOT NULL, -- Who
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
現在のレコードは常にPersonテーブルにあります。変更がある場合、監査レコードが作成され、古いレコードがPerson_Historyテーブルにコピーされます(IDは変更されず、複数のバージョンが存在する可能性があることに注意してください)。
監査IDは* _Historyテーブルにあるため、必要に応じて複数のレコード変更を1つの監査レコードにリンクできます。
編集:
各ベーステーブルに個別の履歴テーブルがなく、同じテーブルを使用して古いレコードと「削除された」レコードを保持する場合は、ステータスフラグでレコードをマークする必要があります。現在のレコードを照会するとき、それは本当の痛みです-私がそれをやったことを信じてください。
通常どおりにテーブルを作成し、各レコードにModifiedDate列(および必要に応じてModifiedBy)を設定し、IDによってデータをグループ化したマテリアライズドビューを介してすべてのデータアクセスを実行してから、HAVING ModifiedDate = MAX(ModifiedDate )?
このようにして、別のレコードと同じIDを持つ新しいレコードを追加すると、ビューから古いレコードが削除されます。履歴を照会する場合は、ビューを経由しないでください
私はいつも同じColmで異なるテーブルを維持することは複雑でエラーが発生しやすいことを発見しました。
ベーステーブルごとに履歴テーブルを使用するDJの投稿と、起こりうるパフォーマンスの問題に関するKarlのコメントに続いて、テーブル間でレコードを転送するための最速の方法を理解するために、少しSQLの調査を行いました。
私は見つけたものを文書化したかっただけです:
SQLフェッチを実行してレコードをベーステーブルからロードし、SQLプッシュを実行してレコードを履歴テーブルに配置し、ベーステーブルを更新して変更されたデータを挿入する必要があると考えました。合計3つのトランザクション。
しかし、驚いたことに、SELECT INTO構文を使用する1つのSQLステートメントを使用して、最初の2つのトランザクションを実行できることに気付きました。これを行うとパフォーマンスが100倍速くなると私は賭けています。
その後、ベーステーブル内の新しいデータでレコードを更新するだけです。
私はまだ3つのトランザクションすべてを一度に実行する1つのSQLステートメントを見つけていません(私がそうするかどうかは疑問です)。
私はあなたの監査テーブルが好きです、それは良いスタートです。監査テーブルにカーディナリティの問題があるので、2つのテーブルとしてバストアウトします。
Person
------------------------------------------------
ID UINT NOT NULL,
PersonID UINT NOT NULL,
Name VARCHAR(200) NOT NULL,
DOB DATE NOT NULL,
Email VARCHAR(100) NOT NULL,
AuditID UINT NOT NULL
Audit
------------------------------------------------
ID UINT NOT NULL,
TableName VARCHAR(50) NOT NULL, -- What
TableKey UINT NOT NULL,
CreateDate DATETIME NOT NULL DEFAULT(NOW),
CreateUserID UINT NOT NULL,
ChangeDate DATETIME NOT NULL DEFAULT(NOW),
ChangeUserID UINT NOT NULL
Audit_Item
------------------------------------------------
ID UINT NOT NULL,
AuditID UINT NOT NULL, -- Which audit record
UserID UINT NOT NULL, -- Who
OldRecID UINT NOT NULL, -- Where
NewRecID UINT NOT NULL,
AffectedOn DATE NOT NULL, -- When
Comment VARCHAR(500) NOT NULL -- Why
提案された最初のレイアウトには、2つのPersonレコードを指す(私はそう思います)単一の監査レコードがあります。この設計の課題は次のとおりです。
WHERE TableName='Person'
句を使用してAuditテーブルにクエリを実行しなくても、Auditテーブルに戻り、個々のPersonの履歴を取得できます。