ソフトデリート vs ハードデリート:適切なデータライフサイクルを選ぶ
ソフトデリートとハードデリートの違いを学び、履歴を残しつつ参照切れを防ぎ、プライバシー削除要件にも対応するための明確なルールを作る方法。

ソフトデリートとハードデリートが本当に意味するもの
「削除」は二つのまったく異なる意味を持つことがあります。混同すると履歴を失ったり、プライバシー要求に対応できなくなったりします。
ハードデリートは一般に想像される通りです:行がデータベースから取り除かれ、後でクエリしても存在しません。これは真の削除ですが、設計をしないと参照(たとえば削除された顧客を指す注文)が壊れる可能性があります。
ソフトデリートは行を残しつつ deleted_at や is_deleted のようなフィールドで削除済みとマークします。アプリからは存在しない扱いにできますが、レポートやサポート、監査のためにデータは残ります。
「ソフトデリート vs ハードデリート」のトレードオフはシンプルです:履歴か真の削除か。ソフトデリートは履歴を守り、元に戻すことを可能にします。ハードデリートは保存データを減らし、プライバシーやセキュリティ、法的要件に関わる点で重要です。
削除は単に保存領域に影響するだけでなく、チームが後で何に答えられるかを変えます:過去の苦情を理解しようとするサポート担当、請求を照合する経理、誰がいつ何を変更したかを確認するコンプライアンスなどです。データが早すぎる段階で消えると、レポートの値が変わり、合計が合わなくなり、調査が推測になってしまいます。
役立つ考え方:
- ソフトデリートは日常の表示からレコードを隠しますが、追跡性のために保持します。
- ハードデリートはレコードを永久に削除し、保存される個人データを最小化します。
- 多くの実アプリでは両方を使います:業務上の記録は保持し、必要に応じて個人識別子を削除・匿名化します。
実務では、ユーザーアカウントをログイン不可にするためにソフトデリートし、注文履歴は残し、保持期間や確認済みのGDPRの消去要求に応じて個人フィールドをハードデリート(または匿名化)する、という運用がありえます。
ツールがこの決定を代わりに行ってくれるわけではありません。AppMasterのようなノーコードプラットフォームを使っている場合でも、テーブルごとに「削除」が何を意味するかを決め、全ての画面・レポート・APIが同じルールに従うようにするのが本質的な作業です。
日常のアプリで削除が引き起こす本当の問題
ほとんどのチームは問題が発生して初めて削除に気づきます。「単純な」削除がコンテキストや履歴、説明能力を消してしまうことがあります。
ハードデリートは元に戻しにくいためリスクが高いです。誤操作でボタンを押されたり、自動ジョブにバグがあったり、サポート担当が誤った手順を踏んだりします。クリーンなバックアップと復元プロセスがなければ、その損失は永久になり、ビジネスへの影響がすぐに現れます。
次の驚きは参照の破壊です。顧客を削除したが注文は残る、という状況になると、注文が存在するのに顧客を表示できず、請求書に請求先名が出せず、関連データを読み込もうとしてポータルがエラーになります。外部キー制約があっても「修正」がより大きな問題を引き起こすことがあります:カスケード削除が意図せず多くのデータを消してしまう場合です。
解析・レポーティングも混乱します。古いレコードが消えると過去の指標が遡って変わることがあります。先月のコンバージョン率が変わり、ライフタイムバリューが下がり、トレンドに説明のつかない穴が開きます。チームは数字の議論に時間を取られ、意思決定が遅れます。
サポートとコンプライアンスでは特に痛手になります。「なぜ請求されたのか」「誰がプランを変えたのか」という問いに対してレコードがなければタイムラインを再構築できません。何が、いつ、誰によって変更されたかを答える監査証跡を失います。
ソフトデリート vs ハードデリート論争に関するよくある失敗パターン:
- 誤削除やバグある自動化による永久的な喪失
- 親レコードが欠けて子が孤立する(注文やチケット)
- 履歴行が消えることで変わるレポート
- 履歴がないために回答不能になるサポート案件
ソフトデリートをデフォルトにすべきとき
レコードに長期的価値がある、あるいは他データと結びついている場合、ソフトデリートが安全な選択です。行を削除する代わりに deleted_at や is_deleted のようにマークし、通常のビューからは隠します。ソフトデリートをデフォルトにすることで後の驚きを減らせます。
これは特にデータベースの監査ログが必要な場所で有効です。運用チームは「誰がこの注文を変えたか?」や「なぜこの請求書がキャンセルされたか?」といった単純な質問に答える必要があります。早期にハードデリートすると、経理・サポート・コンプライアンスの報告に必要な証拠を失います。
ソフトデリートは「元に戻す」を可能にします。管理者は誤って閉じたチケットを復元したり、アーカイブした商品を戻したり、誤判定されたスパムで削除されたユーザー生成コンテンツを回復したりできます。データが物理的に消えているとこの種の復元は困難です。
リレーションの面でも有利です。親行をハード削除すると外部キー制約が壊れたり、レポートに空白が生じたりします。ソフトデリートなら結合は安定し、日別収益や完了した注文数などの履歴合計が一貫します。
ソフトデリートは、サポートチケット、メッセージ、注文、請求書、監査ログ、アクティビティ履歴、ユーザープロフィール(最終的な削除が確定するまでは)などの業務記録のデフォルトとして強く推奨されます。
例:サポート担当が誤りを含む注文メモを「削除」した場合、ソフトデリートなら通常のUIからは見えなくなりますが、苦情が来たときに管理者は内容を確認でき、経理レポートも説明可能なままです。
ハードデリートが必要な場合
ソフトデリートは多くのアプリで良いデフォルトですが、データを保持すること自体が誤りとなる場合があります。ハードデリートは行を完全に削除するので、法的・セキュリティ的・コスト面の要件に適合する唯一の選択肢になることがあります。
もっとも明確なケースはプライバシーや契約上の義務です。個人がGDPRの消去権を行使した場合や、契約で一定期間後に削除することを約束している場合、単に「削除済み」とマークするだけでは不十分なことがあります。行やそのコピー、個人を特定できる識別子を削除する必要が出てきます。
セキュリティも理由になります。生のアクセス・トークン、パスワードリセットコード、秘密鍵、ワンタイムコード、暗号化されていない機密情報などは保持すべきではありません。履歴のために残す利点はほとんどありません。
スケールの観点でもハードデリートが適切な場合があります。古いイベントやログ、テレメトリの巨大なテーブルをソフトデリートで残すとデータベースが静かに膨らみ、クエリが遅くなります。計画的なパージはシステムの応答性とコスト予測性を保ちます。
ハードデリートは一時データ(キャッシュ、セッション、ドラフトインポート)、短命のセキュリティアーティファクト(リセットトークン、OTP、招待コード)、テスト/デモアカウント、大規模な履歴データセット(集計のみを保持する場合)に適しています。
実用的には「業務履歴」と「個人データ」を分けるとよいでしょう。たとえば会計のために請求書は残し、個人を特定するプロフィールフィールドはハードデリートや匿名化する、という方針です。
チームで議論するときは簡単なテストを:保持することで法的・セキュリティ上のリスクが生じるなら、ハードデリート(または不可逆な匿名化)を選びましょう。
予期せぬ問題を起こさないソフトデリートの設計法
ソフトデリートは退屈で予測可能であることが最良です。目的はシンプル:レコードはデータベースに残るが通常のアプリ部分は存在しないかのように振る舞うことです。
削除のシグナルを一つ選び、その意味を明確にする
よくあるパターンは deleted_at タイムスタンプ、is_deleted フラグ、またはステータス列(enum)です。deleted_at は「削除されているか」と「いつ削除されたか」の二つを同時に答えられるため多くのチームに好まれます。
既にライフサイクルに複数の状態(active, pending, suspended)があるならステータス列でも構いませんが、「deleted」は「archived」や「deactivated」と明確に分けておくべきです。違いは以下の通り:
- Deleted:通常の一覧に現れず、利用できないもの。
- Archived:履歴として保持されるが「過去の表示」では見えるもの。
- Deactivated:一時的に無効で、ユーザー側で元に戻せることが多いもの。
一意性フィールドへの対処を先に考える
ソフトデリート vs ハードデリートの問題はメールやユーザー名、注文番号のような一意性フィールドでよく発生します。削除済みでもメールが残ると同じ人が再登録できなくなります。
二つの一般的な対策:
- 一意性制約を非削除行にのみ適用する。
- 削除時に値を書き換えて(一意性を壊さないよう)上書きする。
どちらを採るかはプライバシーと監査要件次第です。
フィルタルールを明確に(一貫して)する
誰が何を見られるかを決めてください。一般的なルールは:通常ユーザーは削除済みを見ない、サポート/管理者はラベル付きで見られる、エクスポートやレポートは明示的に要求された場合のみ含める、です。
「みんながフィルタを入れ忘れないようにする」ことに頼らないでください。フィルタを一箇所に置く:ビュー、デフォルトクエリ、あるいはデータアクセス層に実装しましょう。AppMasterで構築する場合は、エンドポイントやビジネスプロセスでフィルタを組み込んでおくと、削除済み行が誤って再表示されるのを防げます。
短い内部メモ(またはスキーマコメント)に意味を書き残しておくとよいでしょう。「deleted」「archived」「deactivated」が同じ会議に出てきたときに未来のあなたが感謝します。
参照を壊さない:親・子・結合の扱い
削除がアプリを最もよく壊すのはリレーションを通じてです。レコードは単独で存在することは稀で、ユーザーには注文があり、チケットにはコメントがあり、プロジェクトにはファイルがあります。ソフトデリート vs ハードデリートの難しさは、参照の整合性を保ちながらユーザーには「消えた」ように見せることです。
外部キー:失敗モードを意図的に選ぶ
外部キーは参照切れを防ぎますが、各オプションは異なる意味を持ちます:
- RESTRICT は子レコードがある場合に削除をブロックします。
- SET NULL は削除を許しますが、子の接続が切れます。
- CASCADE は子も自動削除します。
- NO ACTION は多くのDBで RESTRICT に似ていますがタイミングが異なることがあります。
ソフトデリートを使う場合、RESTRICT が安全なデフォルトであることが多いです。行を保持するのでキーは有効なままになり、子が何も指さなくなるのを避けられます。
リレーションでのソフトデリート:孤立させずに隠す
ソフトデリートでは通常外部キーを変更しません。代わりにアプリやレポートで削除済みの親をフィルタします。顧客がソフトデリートされていても請求書は正常に結合されるべきで、画面上のドロップダウンに顧客が表示されないようにする、という運用です。
添付ファイル、コメント、アクティビティログについては「削除」の意味をユーザー向けに決めてください。プライバシー要件があるなら内容をプレースホルダに置き換える、コメントの著者を「削除ユーザー」としてマークする(または匿名化する)、アクティビティログは不変のまま保持する、といった選択肢があります。
結合とレポーティングには明確なルールが必要です:削除済み行を含めるか? 多くのチームは「アクティブのみ」と「削除含む」の二つの標準クエリを用意し、サポートやレポートで重要な履歴が誤って隠れないようにしています。
ステップバイステップ:両方を使うデータライフサイクル設計
実用的なポリシーは多くの場合、日常のミスにはソフトデリート、法的・プライバシー要件にはハードデリートを使う組み合わせです。一つの判断(ソフトかハードか)だけで考えると中間の解が見えなくなります:履歴を一定期間保持してから削除する、という中間運用です。
シンプルな5ステップ計画
データをいくつかのグループに分けます。たとえば「ユーザープロフィール」は個人データ、「トランザクション」は会計記録、「ログ」はシステム履歴です。各グループでルールが異なります。
多くのチームで有効な短い計画:
- データグループとオーナーを定義し、誰が削除を承認するか決める。
- 保持期間と復元ルールを設定する。
- 削除ではなく匿名化するデータを決める。
- タイムドパージ(ソフトデリート→一定期間後にハードデリート)を追加する。
- 削除・復元・パージのたびに監査イベントを記録する(誰が、いつ、何を、なぜ)。
具体例で実装をイメージする
顧客がアカウントの閉鎖を求めたとします。まず即座にユーザーをソフトデリートしてログイン不可にし、参照を壊さないようにします。次に保持すべきでない個人フィールド(名前、メール、電話)を匿名化し、会計のために必要な非個人の取引情報は残します。最後にスケジュールされたパージジョブが待機期間後に残る個人情報を削除します。
避けるべきよくある間違いと落とし穴
チームが問題に陥るのは間違ったアプローチを選ぶからではなく、均一に適用していないからです。「ソフトとハードの使い分け」は方針として存在しても、実際は一つの画面で隠すだけでAPIやCSV、管理ツール、同期ジョブでは残っている、ということがよくあります。メールリストやモバイル検索に「削除済み」顧客が現れるとユーザーは気づきます。
レポートと検索は別の落とし穴です。レポートクエリが削除済み行を一貫してフィルタしていないと合計が変わり、ダッシュボードの信頼性が失われます。最悪の場合はバックグラウンドジョブが再インデックスしたり削除済みアイテムを再送したりします。
ハードデリートが行き過ぎるケースもあります。単一のカスケード削除が注文・請求書・メッセージ・ログを一度に消してしまい、本来必要だった監査証跡まで失うことがあるため、ハードデリートを使う場合は何を消してよいか明確にする必要があります。
ソフトデリートでは一意性制約が微妙な問題を引き起こします。ユーザーがアカウントを削除して同じメールで再登録しようとすると古い行が残っているせいで失敗することがあります。これを早い段階で想定しておきましょう。
コンプライアンスチームは「削除がいつ実行されたかを証明できるか」を問います。「削除したはずだ」だけでは不十分です。削除タイムスタンプ、誰が/何が実行したか、理由を記録してください。
公開前に以下をサニティチェックしてください:API、エクスポート、検索、レポート、バックグラウンドジョブ。テーブルごとのカスケードも確認し、再登録可能な一意データ(メールやユーザー名)をユーザーが再作成できるかも確認します。
出荷前のクイックチェックリスト
ソフトデリート vs ハードデリートを選ぶ前に、スキーマだけでなくアプリの実際の挙動を確認してください。
- 復元は安全で予測可能か:管理者が復元したときに、取り戻すべきでないもの(取り消されたアクセス・トークン等)が復活しないか?
- クエリはデフォルトで削除データを隠すか:新しい画面やエクスポート、APIが誤って削除行を含めないようにしているか?
- 参照は壊れないか:外部キーや結合が孤立したレコードや半分空の画面を作らないか?
- パージにはスケジュールと責任者がいるか:ソフトデリートは計画の半分に過ぎません。いつ完全削除するか、誰が実行するか、何を除外するか(例:進行中の異議申立て)が定義されているか?
- 削除は他の重要操作と同様にログに残るか:誰が実行し、いつ行い、理由は何かを記録する。
次にプライバシーパスをエンドツーエンドでテストしてください。GDPRの消去要求をメインDBだけでなく、コピー、エクスポート、検索インデックス、分析テーブル、連携先に対しても履行できるか?
実用的な検証方法の一つは、ステージング環境で一度「ユーザー削除」のドライランを行い、データの流れを辿ることです。
例:請求履歴を残してユーザーを削除する
顧客から「アカウントを削除してほしい」と依頼が来ました。一方で会計上は請求書を保持する必要があります。ここでソフトデリートとハードデリートが実用性を持ちます:アクセスと個人情報を削除または匿名化し、財務記録は残すことができます。
「アカウント」と「請求記録」を分けて考えてください。アカウントはログインと識別に関するもの、請求記録は既に発生した取引に関するものです。
きれいな実装例:
- ユーザーアカウントをソフトデリートしてログイン不可にし、通常表示から消す。
- 請求書や支払いは会計上の記録として残すが、個人を特定できるフィールドとは結びつけないようにする。
- 個人データ(名前、メール、電話、住所)は「Deleted User」などの中立的な値と内部参照に置き換えて匿名化する。
- APIトークン、パスワードハッシュ、セッション、リフレッシュトークン、記憶デバイスなどの機密アイテムはハードデリートする。
- 実際に必要なコンプライアンスとサポート情報だけを残し、理由を文書化する。
サポートチケットやメッセージは中間に位置することが多いです。メッセージ本文に個人データが含まれる場合は部分的に削除・伏字にする、添付を削除する、チケットの外枠(タイムスタンプ、カテゴリ、解決状況)だけを保持する、といった対応が必要になることがあります。送信済みの識別子(メール/電話番号)も削除して再連絡されないようにします。
サポートが見られるのは通常、請求番号、日付、金額、ステータス、ユーザーがいつ削除されたかの注記などであり、ログインメールやフルネーム、住所、保存された支払い方法の詳細、アクティブなセッションなどの個人を特定できる情報は見られないようにします。
次のステップ:ルールを決め、一貫して実装する
削除の決定は書面化され、一貫して製品に実装されて初めて定着します。ソフトデリート vs ハードデリートはまず方針の問題として扱ってください。
チーム全員が読める簡潔なデータ保持ポリシーから始めましょう。何を、どれくらいの期間、なぜ保持するのかを明記してください。「なぜ」が重要で、目標が衝突したとき(例:サポート履歴 vs プライバシー要求)にどちらを優先するかを示します。
良いデフォルトは多くの場合:業務レコード(注文、チケット、プロジェクト)はソフトデリート、機密データ(トークン、秘密)はハードデリート、という形です。
方針が明確になったら、それを強制するフローを作りましょう:復元用の「ゴミ箱」ビュー、チェック付きの「パージキュー」、誰が何をいつしたかが見える監査ビュー。パージ操作は削除よりも難しくして誤用を防いでください。
AppMaster(appmaster.io)で実装する場合は、Data Designerでソフトデリート用フィールドをモデリングし、削除・復元・パージのロジックを一つのビジネスプロセスに集約すると、画面やAPI全体で同じルールが自動的に適用されて便利です。
よくある質問
ハードデリートはデータベースから行そのものを物理的に削除するため、後のクエリでは見つかりません。ソフトデリートは行を残して deleted_at のような印で「削除済み」として扱い、通常の画面からは隠しつつサポートや監査、レポート用に履歴を保持します。
注文、請求書、チケット、メッセージ、アカウント活動など、後で説明が必要になる業務レコードにはソフトデリートを標準にするのがよいです。偶発的なデータ損失を減らし、リレーションを維持し、誤操作時の「元に戻す」を容易にします。
保持することでプライバシーやセキュリティのリスクが生じる場合、あるいは保持ルールが真の削除を要求する場合はハードデリートが正解です。具体例としては、パスワードリセットトークン、ワンタイムコード、セッション、APIトークン、個人情報の完全消去が必要な場合などです。
deleted_at は、レコードが削除されているか(存在するか)と、その日時の両方を示すため一般的です。保持期間(例:30日後にパージ)や「いつ削除されたか」を問う監査にも便利で、別途時刻ログを用意する必要が減ります。
メールやユーザー名のようなユニークフィールドは、古い(削除済み)行が値を保持していると再登録を阻むことがあります。一般的な対処法は、ユニーク制約を“非削除行のみ”に適用するか、削除時に値を書き換えて衝突しないようにすることです。どちらを選ぶかはプライバシーと監査要件に依存します。
親レコードをハード削除すると子レコードが孤立したり、カスケードで予期せぬ削除が発生することがあります。ソフトデリートでは外部キー自体は通常変更せず、アプリ側やレポートで削除済み親をフィルタすることで整合性を保ちます。ただしフィルタの適用を一貫させる必要があります。
過去の行をハードデリートすると、過去の合計値が変わったりトレンドに穴が開いたりして、財務の数字やダッシュボードの信頼性が損なわれます。ソフトデリートは履歴を残す助けになりますが、レポート側で削除を含めるか除外するかを明確にして一貫して扱うことが重要です。
“ソフトデリート”だけではGDPRの消去権に対応できない場合があります。実際にはアクセスを即時停止し、識別可能な個人情報は不可逆に匿名化するかハードデリートし、会計や紛争対応に必要な非個人情報だけを残すのが現実的なパターンです。バックアップや外部エクスポートまで含めて対応を検討してください。
復元後に不適切な状態にならないように、復元ルールを明確にする必要があります。たとえばセッションやリセットトークンは復元すべきではない場合や、関連データの整合性(リレーションや権限)が保たれるかの確認が必要です。復元は単にフラグを外すだけで済まないことが多いです。
削除・復元・パージの挙動を一箇所に集約して、すべてのAPI・画面・エクスポート・バッチ処理が同じフィルタを使うようにしましょう。AppMasterでは、Data Designerでソフトデリート用フィールドを定義し、ビジネスプロセスに削除ロジックを実装しておくのが一般的です。


