「念のため残しておいて」が招く論理削除の罠
システム開発の要件定義では、発注側からほぼ必ずと言っていいほど出てくる要望があります。
「データは消さないでほしい。念のために残しておきたい」
この言葉を受けて、設計に「論理削除」を採用することになります。意図は正しいように見えますが、「すべてのテーブルに論理削除を適用する」という方針は、システム全体の品質に大きな影を落とします。
論理削除と物理削除の違い
物理削除は、データベースからレコードを完全に取り除く操作です。DELETE FROM orders WHERE id = 123 を実行すると、そのレコードは存在しなくなります。
論理削除は、削除フラグを立てることで「削除済み」を表現し、レコード自体は残す手法です。実装方式には大きく2種類あります。
タイムスタンプ方式:deleted_at という日時列を設け、削除時にその時刻を記録します。NULLであれば有効なレコード、値が入っていれば削除済みとみなします。「いつ削除されたか」が記録に残る点がメリットです。
フラグ方式:is_deleted = 1 / 0 や is_active = 1 / 0 のような数値フラグ列で状態を管理します。シンプルな実装ですが、削除日時の情報は持ちません。
【タイムスタンプ方式】
通常のレコード: deleted_at = NULL
削除済みレコード: deleted_at = 2026-05-30 10:00:00
【フラグ方式】
通常のレコード: is_deleted = 0
削除済みレコード: is_deleted = 1
本記事では、削除日時の追跡が可能で実務での採用例も多いタイムスタンプ方式を前提に説明します。
論理削除を全適用すると何が起きるか
問題は、「すべての画面・機能で、常に削除フラグを考慮した条件が必要になる」 という点です。
例えば WHERE deleted_at IS NULL という条件を、システム内のすべてのSELECT文に書き忘れずに付与しなければなりません。一箇所でも漏れると、削除済みのはずのデータが画面に表示されます。テーブル数が増え、JOINが複雑になるほど、この「書き忘れ」のリスクは指数的に高まります。
また、ユニーク制約との衝突も発生します。例えば「メールアドレスは一意」という制約があるとき、論理削除されたユーザーのメールアドレスがデータベース上に残り続けると、同じアドレスで新規登録ができなくなります。これを回避するための複雑な条件分岐が追加され、設計がさらに複雑化します。
「念のため残したい」の正体を問い直す
発注側が「データを残したい」と言うとき、その理由はいくつかに分類されます。
監査・証跡として必要なケース
「誰がいつ何を操作したか」を記録したい場合、これは正当な要件です。ただし、この目的には操作ログテーブルを別に設ける設計が適切であり、全テーブルの論理削除とは別の話です。
復元できるようにしたいケース
「誤って消した場合に戻せるようにしたい」という要望です。一定期間はごみ箱に入れておく仕組みや、データベースの定期バックアップで対応できます。すべての業務データを常時保持する必要はありません。
「なんとなく不安」なケース
要件として明確ではなく、「消えたら困るかもしれない」という漠然とした不安から来ていることも少なくありません。この場合は、何のために残すのかをすり合わせることが先決です。
設計レビューで確認すべきポイント
論理削除の採用を提案された際、発注側として確認すべき点は以下の通りです。
- 削除されたデータを、どの画面で、どのような権限で参照するのか
- 削除フラグを考慮したクエリが漏れた場合の影響範囲はどこまでか
- ユニーク制約を持つ列(メールアドレス、コード番号など)との整合性をどう担保するか
- バックアップや操作ログによる代替手段では要件を満たせないか
適切な使い分け
論理削除が適しているのは、削除後も業務上の意味で参照される可能性があるデータです。受注履歴・契約書・請求書など、削除しても「過去の記録」として参照が発生するケースです。
一方、マスターデータの廃止(使わなくなった商品カテゴリ、退職した社員など)は、論理削除よりも「有効フラグ」や「有効期間」として管理する設計の方が意図が明確になります。
「念のため残す」という発想自体は否定しません。しかし、その目的を整理しないまま全テーブルに論理削除を適用することは、システムの複雑性を高め、長期的なメンテナンスコストとバグリスクを発注者自身が負うことになります。