物理削除と論理削除
物理削除と論理削除 とは
物理削除と論理削除の違いを学びます。それぞれのメリット・デメリットを理解しましょう。本レッスンでは、物理削除と論理削除 の基本から実際の使いどころまでを整理し、現場で迷わず使える形に落とし込みます。
なぜ重要か
本番運用が始まると「削除した行を後から復元したい」「監査ログのために退会済ユーザの情報を残したい」というニーズが必ず出てきます。DELETE FROM で行ごと消す物理削除 (hard delete) は素朴で気持ちいいですが、取り返しがつきません。これに対して、行は残したまま「もう存在しないことにする」フラグや時刻を立てる論理削除 (soft delete) という設計テクニックがあります。どちらが正解という話ではなく、業務要件によって使い分けるものです。設計レビューで「ここは物理 / ここは論理」を判断できることが、実務でテーブルを任せられる人の必須条件になります。
2 つの戦略の比較
代表的な実装
SQL クエリ
-- 物理削除
DELETE FROM users WHERE id = 7;
-- 論理削除 (deleted_at が NULL なら有効)
UPDATE users
SET deleted_at = NOW()
WHERE id = 7;論理削除を採用するテーブルは、有効な行だけを取りたいすべての SELECT で WHERE 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 つができることを確認しましょう。
- 物理 vs 論理削除 の要点を自分の言葉で説明できる
- このレッスンの最小コード (または操作手順) を見ずに書ける
- 練習問題やクイズで間違えた箇所を読み直して理解した
理解度チェック (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');期待される出力
| id | name | |
|---|---|---|
| 1 | 田中太郎 | tanaka@example.com |
| 2 | 佐藤花子 | sato@example.com |