仕組みから学ぶ Web
応用読了目安 14#論理削除#物理削除#一意制約#個人情報

論理削除と物理削除 — 「消した」を、すべてのクエリが覚えていられるか

退会した会員にキャンペーンメールが届いた。論理削除は、削除を DB の操作から、すべてのクエリが守る約束に変える。

この記事の進み方

What — 行を消すか、印を付けるか

削除には2つのやり方があります。

  • 物理削除DELETE で行そのものを消す。テーブルから無くなる
  • 論理削除 — 行は残し、「削除済み」の印(deleted_atis_deleted)を付ける。読むときに印の付いた行を除く

一見、論理削除は「消さないだけ」の安全な選択に見えます。ところが、「削除」という事実の置き場所が変わっています

Compare削除のやり方

消したことを DB が保証する

DELETE FROM members WHERE id = 42
消えたことを守る人
DB
読むときの条件
要らない
復元
バックアップからしかできない
一意制約・外部キー
そのまま正しく効く
  • 消した行は、どのクエリからも見えない。書き忘れという事故が起きない
  • 外部キーが参照していれば、消す時点で DB が止めるか、連動させる
  • 「いつ、誰が消したか」は残らない。必要なら別に記録する

違いは「消えるかどうか」ではなく、「消えたことを誰が守っているか」。物理削除では DB が守り、論理削除ではすべてのクエリが守る。

物理削除
DELETE で行そのものを消すこと。ハードデリートとも呼ぶ。
論理削除
行を残したまま、削除済みの印を付けること。ソフトデリートとも呼ぶ。
一意制約
列の値がテーブル内で重複しないことを DB が保証する制約。
部分インデックス
条件を満たす行だけを対象にするインデックス。使える DB と使えない DB がある。
確認 — ここまで読めたか

会員テーブルを論理削除にしています。退会した人が同じメールアドレスで再登録しようとすると「登録済み」で弾かれます。原因はどれですか?

まず選ぶ(解答例は a〜d の記号で説明します)

Why — なぜ事故になるのか

物理削除では、「その行はもう無い」という事実を DB が守っています。消えた行はどの SELECT にも出てきません。書き忘れようがありません。

論理削除にすると、この事実は DB の外に出ます。deleted_at が入っている行は無いものとして扱う」という約束に変わり、その約束を守るのは、テーブルを読むすべてのクエリです。

物理削除:  DB が「無い」を保証する   → 読む側は何も知らなくてよい
論理削除:  読む側が「無い」を再現する → 読む側全員が約束を知っている必要がある

アプリのコードだけなら、レビューや共通の関数で守れるかもしれません。ところがテーブルを読むのはアプリだけではありません。配信ツール、分析基盤、管理画面、障害対応で誰かが手で書く SQL。 その全員が約束を知っていることは、誰も保証していません。

制約も、削除を知らない

冒頭のもう1つの事故、再登録できない問題も同じ根から来ています。

一意制約も外部キーも、DB の上の「行」について約束するものです。deleted_at は、DB から見ればただの列の1つにすぎません。

  • 一意制約 は、削除済みの行も数える。再登録が弾かれる
  • 外部キー は、削除済みの親を「存在する」と見なす。退会した会員の注文も、参照先が有効なまま残る
  • インデックス は、削除済みの行も含めて大きくなる。削除済みが9割のテーブルでも、索引は10割ぶん

「消した」と言える状態か

論理削除した行には、氏名もメールアドレスも住所も残っています。アプリの画面から見えないことと、消えていることは別です。

個人情報保護法には、利用する必要がなくなった個人データを遅滞なく消去するよう努める、という規定があります。「退会したので消しました」と利用者に説明するなら、少なくとも個人を特定できる情報は、実際に消えているか、特定できない形に置き換わっている必要があります。

論理削除を選ぶとき、ここが最も見落とされます。「戻せるから安全」は、運営者にとっての安全で、利用者にとっての安全ではありません。

確認 — ここまで読めたか

会員を論理削除しました。その会員に紐づく注文は注文テーブルに残っています。外部キー制約はこの状態をどう扱いますか?

まず選ぶ(解答例は a〜d の記号で説明します)

演習 — まず自分で判断する

解説を読む前に、まず自分で判断してみてください。ここで一度詰まっておくと、 次の節の判断軸が「なるほど」ではなく「そう来たか」に変わります。

演習 — 設計判断を問う

会員の退会を、どう実装しますか?

与えられた条件
  • 退会から30日間は、問い合わせがあれば復帰できるようにしたい
  • 注文の記録は、会計上7年残す必要がある
  • 会員テーブルは、アプリのほかに配信ツール・分析基盤・CS の管理画面が読む(別チームを含む)
  • 退会した人の氏名・メールアドレス・住所は、不要になったら消したい
  • 退会した人が、同じメールアドレスで再登録できる
この軸で考える
  • · 「削除」という言葉に、いくつの要求が混ざっているか
  • · アプリの外から読まれたとき、退会者がどう見えるか
  • · 注文を残すことと、個人情報を消すことを両立できるか
まず選ぶ(解答例は a〜d の記号で説明します)

演習 — 説明できるか

「全部論理削除にしておけば、間違えて消しても戻せるから安全」と言う同僚に、何が安全で何が危ないのかを説明してください

与えられた条件
  • 相手は論理削除を何度も使ってきた経験がある
  • 過去に物理削除で本番データを消して、バックアップから戻した経験がある
  • 頭ごなしに否定されると聞き入れにくい

読み終わりましたか?

読了にすると、これを前提とする記事がロードマップで開放されます。