はじめに
システム設計をしていると、必ず「データをどう削除するか」や「変更の履歴をどう残すか」というテーマに直面します。
単純に消すだけでは監査性やユーザー対応に支障が出る一方で、残しすぎてもパフォーマンスが落ちます。
本記事では「削除設計」と「履歴テーブル設計」をそれぞれ整理し、それぞれの実装パターンや注意点をまとめます。
削除設計について
物理削除
データベースからレコードを完全に取り除く方式で、DELETE文を実行するとそのデータは物理的に消去される。
シンプルで直感的な仕組みのため、アプリケーションの実装も分かりやすく、また不要なデータを保持しないためテーブルが肥大化せず、パフォーマンス面でも有利に働くことが多い。
ただし、削除したデータは二度と復元できないため、誤って消してしまった場合のリスクは大きくなる。
さらに、削除の履歴が残らないため、誰がいつ削除したのかといった監査証跡を確保することができない。
業務システムにおいてはこの点が問題になりやすく、後から「本当に削除してよかったのか」「なぜ消えているのか」といった検証ができなくなるのが大きなデメリットとなる。
上記から、物理削除は、シンプルさとパフォーマンスに優れる反面、データ保全や監査の観点では弱点を抱える方式だと言える。
論理削除
論理削除は、データ自体を物理的に消さずに、フラグや削除日時を持たせることで「削除済み」と扱う方式。
たとえばis_deleted
カラムでシンプルに削除状態を管理したり、deleted_at
で削除された日時を記録する実装がよく使われる。
さらに、上記deleted_at
に加えてdeleted_by
のような「削除者ID」を残すことで、誰がいつ削除したのかを正確に追跡できるようになる。
この方式の最大の利点は、データを論理的に残しているため誤って削除しても復元が容易であること、そして削除の証跡をきちんと残せる点にある。
業務システムや監査が必要な領域では特に有効で、データの消失リスクを避けながら「削除」という運用上の要件を満たせる仕組みとして採用されている。
フラグかdeleted_at
+deleted_by
か
最低限で済ませたい場合
単純に「削除済みかどうか」さえ分かればよいので、is_deleted のみで良い。
検索条件にも入れやすく、実装もシンプル。
いつ削除したかが重要な場合
たとえば「30日以内に削除したユーザーを復元できる」といった要件がある場合は、deleted_at
を持たせて日時を管理するのが必須。
監査や責任の所在まで求められる場合
「誰が消したか」を必ず追えるようにしたいなら、deleted_by
も持たせてセットで管理する必要がある。
用途によって使い分けるのが良さそう
履歴テーブル設計について
履歴テーブルの役割
更新や削除の前後状態を別テーブルに記録し、「過去どうだったか」を追えるようにする仕組み。
履歴テーブルは「更新内容そのもの」を残す。
履歴テーブルと監査ログの違い
- 履歴テーブル
値の変化を残す(A→Bに変わった、など) - 監査ログ
誰が・いつ・どんな操作をしたかを残す
両者は似ているが、目的が違うため、実務では併用される。
たとえば「金額を10,000円から12,000円に変更した履歴」は履歴テーブルに、「その操作を◯◯さんが2025/09/30に行った」は監査ログに残すイメージ。
履歴の保存パターン
①差分保存
変更のあったカラムだけ保存する。
データ量を抑えられるが、参照時に復元が複雑になる。
②スナップショット保存
全カラムをコピーして保存する。
過去の状態を簡単に再現できるが、データ量が膨大になる。
多くの業務システムでは「読みやすさ優先」でスナップショット方式を選ぶケースが多いらしい。
まとめ
論理削除は復元や監査対応に便利ですが、データが残り続けるためテーブル肥大化によるパフォーマンス低下に注意が必要ということがわかりました。
履歴テーブルは論理削除とは違い、「データがどう変化したか」を追える仕組みだと整理できました。監査ログが操作主体を記録するのに対し、履歴テーブルは内容の変化そのものを残すので、両方を併用するのが良さそうと思いました。
また、差分保存とスナップショット保存にはそれぞれ利点と欠点があり、要件に応じた選択が必要だと学びました。