物理削除と論理削除

物理削除と論理削除 とは

物理削除と論理削除の違いを学びます。それぞれのメリット・デメリットを理解しましょう。本レッスンでは、物理削除と論理削除 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。

なぜ重要か

本番運用が始まると「削除した行を後から復元したい」「監査ログのために退会済ユーザの情報を残したい」というニーズが必ず出てきます。DELETE FROM で行ごと消す物理削除 (hard delete) は素朴で気持ちいいですが、取り返しがつきません。これに対して、行は残したまま「もう存在しないことにする」フラグや時刻を立てる論理削除 (soft delete) という設計テクニックがあります。どちらが正解という話ではなく、業務要件によって使い分けるものです。設計レビューで「ここは物理 / ここは論理」を判断できることが、実務でテーブルを任せられる人の必須条件になります。

2 つの戦略の比較

diagram (will load when visible)

代表的な実装

SQL クエリ

-- 物理削除 DELETE FROM users WHERE id = 7; -- 論理削除 (deleted_at が NULL なら有効) UPDATE users SET deleted_at = NOW() WHERE id = 7;

論理削除を採用するテーブルは、有効な行だけを取りたいすべての SELECTWHERE deleted_at IS NULL を付ける必要があります。これを忘れると「退会済ユーザがまだログインできる」状態になりかねません。

SQL クエリ

-- 退会していないユーザだけ取る SELECT id, name FROM users WHERE deleted_at IS NULL;

多くの ORM や Repository 層では、論理削除フラグを自動的に WHERE に注入する仕組みを持っています。

使い分けの目安

状況推奨戦略
個人情報、削除権利の行使 (GDPR / 個人情報保護法)物理削除
監査ログ、誤操作からの復元、退会ユーザの実績集計論理削除
一時的なテストデータ、明らかにゴミ物理削除
注文 / 取引履歴のように消えると会計が壊れる論理削除

論理削除でも残らない情報がある

論理削除は便利ですが、個人情報を保持し続けてよい理由にはなりません。GDPR や日本の個人情報保護法では「削除請求があった個人情報は応じる」必要があり、deleted_at を立てるだけでは応じたことになりません。氏名・メール・住所等は別途マスクするか、物理削除します。

論理削除のバリエーション

テーブル設計者の好みやチームのガイドラインによって、論理削除の実装には複数のスタイルがあります。

SQL クエリ

-- A. deleted_at (時刻) を持つスタイル ALTER TABLE users ADD COLUMN deleted_at TIMESTAMP NULL; -- WHERE deleted_at IS NULL で有効行を絞る -- B. is_deleted (ブール) を持つスタイル ALTER TABLE users ADD COLUMN is_deleted INT NOT NULL DEFAULT 0; -- WHERE is_deleted = 0 で有効行を絞る -- C. status (列挙) で active / archived / deleted を分けるスタイル ALTER TABLE users ADD COLUMN status VARCHAR(20) NOT NULL DEFAULT 'active'; -- WHERE status = 'active' で有効行を絞る

どれが正解ということはなく、「いつ削除されたかを残したいか」「他にも状態が必要か」で選びます。深い理由なく混ぜると、テーブル毎に書き方が違って Repository がカオスになるので、プロジェクトで 1 つに統一するのがおすすめです。

論理削除を採用するテーブルでは、すべての SELECT に WHERE deleted_at IS NULL を入れるのが鉄則です。これをアプリ側の Repository 層で強制すると漏れが減ります。

論理削除を採用すると、UNIQUE 制約と相性が悪くなることがあります。たとえば「メールアドレスは UNIQUE」でも、退会して再登録した時に古い行が残っていると UNIQUE 違反になります。UNIQUE (email, deleted_at) のような複合 UNIQUE で逃げるテクニックがあります。

注意 論理削除のテーブルで SELECT * FROM users をうっかり書くと、退会済も含めた全ユーザが取れてしまいます。本番でログイン画面のパスワード照合に使うと「退会済でログインできる」事故になります。

まとめ

  • 物理削除 = 行が消える、論理削除 = フラグや時刻で「無いことにする」
  • 復元したい、監査したい、集計に残したい場合は論理削除
  • 個人情報の削除請求は論理削除では応えられない、物理削除またはマスクが必要
  • 論理削除を採用したら、SELECT で WHERE deleted_at IS NULL を必ず付ける
  • UNIQUE 制約は (列, deleted_at) のような複合で再登録に対応する

次のレッスン

次は ALTER TABLE で構造を変更する です。ALTER TABLEを使ってテーブルの構造を変更する方法を学びます。カラムの追加や変更を実践!

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. 物理 vs 論理削除 の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. 物理 vs 論理削除 とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

テーブル構造

schema.sql

CREATE TABLE users ( id INT PRIMARY KEY, name VARCHAR(100) NOT NULL, email VARCHAR(255) NOT NULL, deleted_at TIMESTAMP NULL ); INSERT INTO users (id, name, email, deleted_at) VALUES (1, '田中太郎', 'tanaka@example.com', NULL), (2, '佐藤花子', 'sato@example.com', NULL), (3, '退会済 A', 'old-a@example.com', '2024-12-01 10:00:00'), (4, '山田次郎', 'yamada@example.com', NULL), (5, '退会済 B', 'old-b@example.com', '2025-01-15 09:30:00');

期待される出力

idnameemail
1田中太郎tanaka@example.com
2佐藤花子sato@example.com

ヒント

query.sql
query.sql
学習モード
コードの実行結果
データベースを初期化中...