以下のような構造の非常に単純な tablestudents
があり、主キーはid
です。このテーブルは、頻繁に結合される約 2,000 万行のテーブルの代役です。
+----+----------+------------+ | | ID | 名前 | ドブ | ドブ | +----+----------+------------+ | | 1 | アリス | 1989 年 1 月 12 日 | | | 2 | ボブ | 1990 年 4 月 6 日 | | | 3 | カスバート | 1988 年 1 月 23 日 | +----+----------+------------+
ボブが生年月日を変更したい場合、いくつかの選択肢があります。
students
新しい生年月日で更新します。長所: 1 つの DML 操作。このテーブルには、1 回の主キー検索で常にアクセスできます。
悪い点:ボブが自分の誕生日を 1990 年 4 月 6 日だと思っていたという事実を忘れてしまった
列 をテーブルに追加し
created date default sysdate
、主キーを に変更しますid, created
。すべては次のupdate
ようになります。insert into students(id, name, dob) values (:id, :name, :new_dob)
次に、最新の情報が必要なときはいつでも次のことを行います (Oracle ですが、質問はすべての RDBMS を表します)。
select id, name, dob from ( select a.*, rank() over ( partition by id order by created desc ) as "rank" from students a ) where "rank" = 1
良い点:情報を失うことはありません。
欠点:データベース全体に対するすべてのクエリには、少し時間がかかります。テーブルが指定されたサイズである場合、これは問題ではありませんが
left outer join
、一意のスキャンではなく範囲スキャンを使用して 5 番目になると、効果が現れ始めます。別の列を追加する
deleted date default to_date('2100/01/01','yyyy/mm/dd')
か、または過度に早い、または未来的な日付が好きです。主キーを次のように変更しid, deleted
ますupdate
。update students x set deleted = sysdate where id = :id and deleted = ( select max(deleted) from students where id = x.id ); insert into students(id, name, dob) values ( :id, :name, :new_dob );
現在の情報を取得するクエリは次のようになります。
select id, name, dob from ( select a.*, rank() over ( partition by id order by deleted desc ) as "rank" from students a ) where "rank" = 1
良い点:情報を失うことはありません。
欠点: 2 つの DML 操作。すべてのクエリで一意のインデックス スキャンではなく、追加コストまたは範囲スキャンを使用してランク付けされたクエリを使用する必要があります。
2番目のテーブルを作成し、
student_archive
すべての更新を次のように変更します。insert into student_archive select * from students where id = :id; update students set dob = :newdob where id = :id;
良い点:情報を失うことはありません。
欠点: 2 つの DML 操作。すべての情報を取得したい場合は、使用する必要が
union
あるか、追加のleft outer join
.完全を期すために、恐ろしく非正規化されたデータ構造を持っています
id, name1, dob, name2, dob2...
。
情報を失いたくなく、常に論理的な削除を行う場合、番号 1 はオプションではありません。5 番は、価値以上の問題を引き起こしているため、安全に破棄できます。
オプション 2、3、および 4 には、それに付随するマイナス面が残っています。私は通常、オプション 2 とそれに付随する恐ろしい 150 行 (適切な間隔) の複数のサブ選択結合を使用することになります。
tl;drここで「建設的ではない」投票のライン近くでスケートをしていることに気づきましたが、
データを削除せずに論理的な一貫性を維持するための最適な(特異な!) 方法は何ですか?
私が文書化した方法よりも効率的な方法はありますか? このコンテキストでは、「DML 操作が少ない」および/または「サブクエリを削除できる」ことを効率的と定義します。(もし)答えるときにもっと良い定義を思いつくことができれば、どうぞお気軽に。