私が取り組んでいるプロジェクトでは、さらに監査またはロールバックするために、データベースの一部のテーブルの行に対するすべての変更を追跡する必要があります。その行を誰がどのIPアドレスからいつ変更したかを簡単に見つけ、以前のバージョンを復元できる必要があります。
同様のものが、たとえばStack Exchangeでも使用されています。他の人の質問を変更すると、自分が変更したことがわかり、変更をロールバックできます。
現在のスキーマが平均的なビジネスアプリとほとんど同じプロパティ(以下)を持っている場合、オブジェクトのすべての変更をデータベースに格納するために使用される一般的な手法は何ですか?
- オブジェクトのサイズは比較的小さいです。
nvarchar(1000)
たとえば、バイナリデータの巨大なblobはなくても、ディスクに直接保存され、Microsoft SQL ではなく直接アクセスされる場合がありますfilestream
。 - データベースの負荷はかなり低く、データベース全体はサーバー上の1つの仮想マシンによって処理されます。
- 以前のバージョンへのアクセスは、最新バージョンへのアクセスほど高速である必要はありませんが、それでも最新の状態¹であり、遅すぎない必要があります²。
<tl-dr>
次のようなケースを考えましたが、そういうシナリオはあまり経験がないので、他の人の意見を聞いてみました。
IDとバージョンで行を区別して、すべてを同じテーブルに格納します。IMO、それは深刻な愚かであり、パフォーマンスレベルで遅かれ早かれ傷つけるでしょう。このアプローチでは、最新のアイテムとバージョントレースに異なるセキュリティレベルを設定することも不可能です。最後に、すべてのクエリを記述するのはより複雑になります。実際、最新のデータにアクセスするには、IDですべてをグループ化し、各グループで最後のバージョンを取得する必要があります。
1つのテーブルに最新バージョンを保存し、変更のたびに、古いバージョンを別のスキーマの別のテーブルにコピーします。欠点は、変更されていなくても、常にすべての値を保存することです。変更された値をに設定すること
null
は解決策ではありません。値がに、null
またはに変更されたときにも追跡する必要があるためnull
です。最新バージョンを1つのテーブルに保存し、変更されたプロパティのリストと以前の値を別のテーブルに保存します。これは、二つの傷のようだ:最も重要なのは同じ列に以前の値の異質なタイプをソートする唯一の方法は持っているということです
binary(max)
。2つ目は、以前のバージョンをユーザーに表示するときに、このような構造を使用するのがより困難になると私は考えています。前の2つのポイントと同じことを行いますが、バージョンを別のデータベースに保存します。パフォーマンスに関しては、同じデータベースに以前のバージョンを置くことで最新バージョンへのアクセスが遅くなるのを避けるために興味深いかもしれません。それでも、これは時期尚早の最適化であり、同じデータベースに古いバージョンと最新のバージョンを置くことがボトルネックであるという証拠がある場合にのみ実行する必要があると思います。
</ tl-dr>
¹たとえば、HTTPログの場合と同様に、ログファイルに変更を保存し、サーバーの負荷が最も低い夜間にログからデータベースにデータをフラッシュすることはできません。異なるバージョンに関する情報は、すぐに、またはほぼすぐに入手できる必要があります。数秒の遅延は許容範囲です。
²情報へのアクセスはそれほど頻繁ではなく、特定のユーザーグループのみがアクセスしますが、バージョンのリストが表示されるまで30秒間待つように強制することはできません。この場合も、数秒の遅延は許容されます。