PAP-40-Layer Framework 第29層のアイキャッチ

破壊的操作の対象・承認・ドライラン・復元を確認する

  • URLをコピーしました!

破壊的操作は、削除コマンドの文法が正しいだけでは実行できません。対象の環境・範囲を固定し、確認した計画と承認された内容を一致させ、失敗時にどこまで戻せるかを復元試験で確かめます。対象が曖昧、承認後に条件が変化、復元手段が未確認という状態なら、削除を進めず不足を解消します。

AIには、削除対象の候補や変更案を作らせられます。ただし、その出力だけで実行権限や承認が成立するわけではありません。以下では、一回の削除を判断する流れを、外部へ接続しない架空データで説明します。掲載コード・SQL例は未実行であり、実在のデータを削除した結果ではありません。

目次

「古いデータを消す」を実行可能な対象へ絞る

架空の検証用サービスで、テナントAの期限切れ下書きを整理するとします。対象は検証環境のdraftsというデータ集合で、期限日が2026年6月1日より前、状態がexpired、保全対象ではないレコードに限ります。期限日が当日と等しいものは残す、他テナントは対象外という条件も先に決めます。

ID テナント 期限日 状態 保全指定 期待する扱い
A101 A 2026-05-01 expired なし 削除候補
A102 A 2026-06-01 expired なし 境界日なので保持
A103 A 2026-04-01 expired あり 保全のため保持
A104 A 2026-05-20 expired なし 削除候補
B101 B 2026-04-01 expired なし 別テナントなので保持

ここで「2件を消す」という件数だけを承認対象にすると、A101とA104が別の2件へ入れ替わっても気づけません。ID集合、選定条件、データの版、接続先の識別情報をまとめて計画にします。大量データでは全件を画面に並べる代わりに、完全な対象一覧を保存し、件数・範囲・例外・改変検知用の識別値を表示します。抜粋表示だけで全対象を確認したことにはしません。

実環境では、表示名だけでなくアカウント、プロジェクト、DB、スキーマ、テナント、実行主体を照合します。ファイルなら作業ディレクトリ、絶対パス、シンボリックリンクやマウント先まで対象に含めます。画面に「staging」と書かれていても、実接続が本番であれば停止です。文字列の名前を照合するだけの例を、実接続先の検証へ読み替えないでください。

PostgreSQL 18のDELETEの説明では、WHERE句を省くと表の全行が対象になります。また、権限の要件や継承先への適用も定義されています。行の削除、表そのものの削除、ファイル削除を同じ操作として扱わず、許可する操作種別を固定します。「整理」のために、AIが独断でDELETEをDROPやTRUNCATEへ変更する流れは許可しません。

最初の変更は削除ではなく候補の列挙にする

危険な変更案は、条件式を作った直後に削除を呼び出す構造です。最初の修正として、対象を選ぶ処理を副作用のない計画作成へ切り出します。次はPython 3.14、標準ライブラリだけを想定した説明用コードです。入力は表と同じ架空データで、DB接続、ファイル書込み、削除関数はありません。

from datetime import date

#id, tenant, expires_on, status, legal_hold, revision
rows = (
    ("A101", "A", "2026-05-01", "expired", False, 3),
    ("A102", "A", "2026-06-01", "expired", False, 1),
    ("A103", "A", "2026-04-01", "expired", True, 2),
    ("A104", "A", "2026-05-20", "expired", False, 5),
    ("B101", "B", "2026-04-01", "expired", False, 4),
)

def build_plan(records, *, environment, tenant, cutoff, limit):
    if environment != "fixture-only" or tenant != "A":
        raise ValueError("scope mismatch")
    if type(limit) is not int or limit < 1:
        raise ValueError("invalid limit")
    targets = []
    seen = set()
    for rid, owner, expiry, status, hold, revision in records:
        if rid in seen:
            raise ValueError("duplicate id")
        seen.add(rid)
        expiry_date = date.fromisoformat(expiry)
        if type(hold) is not bool or type(revision) is not int:
            raise ValueError("invalid record")
        if owner == tenant and status == "expired" and not hold:
            if expiry_date < cutoff:
                targets.append((rid, revision))
    if len(targets) > limit:
        raise ValueError("target limit exceeded")
    return {
        "environment": environment,
        "collection": "drafts",
        "tenant": tenant,
        "cutoff_exclusive": cutoff.isoformat(),
        "targets": tuple(sorted(targets)),
    }

#未実行の呼出例。計画を返すだけで削除しない。
plan = build_plan(rows, environment="fixture-only", tenant="A",
                  cutoff=date(2026, 6, 1), limit=2)

期待するtargetsは、A101の版3とA104の版5です。A102は日付条件、A103は保全条件、B101はテナント条件で候補から外れます。入力の重複ID、日付の読取失敗、候補上限超過は、対象を推測して続行せず例外にします。空の候補は削除不要として扱い、条件を緩めて候補を増やしません。

このコードの「fixture-only」は、架空入力を限定するための名前です。認証、実行権限、接続先証明、並行更新の防止を実装したものではありません。本番側では、計画作成役には読取権限だけを与え、実行役には承認された対象へ必要な操作だけを認める仕組みを別に設けます。コマンド文字列に禁止語がないことだけでは、呼出先や引数の安全性は確認できません。

プレビューとドライランで分かることを分ける

プレビューは「何を変える予定か」の表示です。ドライランは、対象ツールが定義する非適用モードなどで手順を試すことですが、何を実行しないのかは製品ごとに違います。名前にdry-runがあっても、接続、ファイル生成、ログ記録、フック呼出しまで無いとは限りません。使用版の仕様を読み、隔離環境で範囲を確かめます。

上の候補一覧はプレビューであり、実DBの削除を試した証拠ではありません。SQLへ置き換える場合も、同じ条件のSELECTは候補の確認に役立つ一方、DELETEで動くトリガー、外部キー処理、ロック競合の全てを再現しません。

特にPostgreSQL 18では、EXPLAINのANALYZEオプションは対象文を実際に実行します。EXPLAIN ANALYZEを削除文へ付けて「確認だけ」と呼ぶのは誤りです。公式資料はトランザクションとROLLBACKによる方法も説明していますが、本番で試す許可や、DB外への副作用まで取り消せる保証を与えるものではありません。本稿では実行例として提示せず、検証環境での計画確認と本操作を分離します。

削除に連鎖する対象も確認します。PostgreSQLの外部キー制約には、参照先の削除に応じたCASCADEやRESTRICTなどの動作があります。親レコード2件のプレビューしか見ていないのに、関連行まで削除される設計なら、承認に必要な影響範囲が欠けています。関連表、トリガー、ジョブ、検索索引や通知連携を調べ、分からない経路は未確認として残します。

ドライランの成功は、そのモードで確認できた条件についての結果です。復元可能性、将来の同時更新、外部通知の取消まで合格に広げないことが重要です。確認結果にはモード、実接続の有無、変更された資源、検査しなかった影響を添えます。

たとえば、候補を列挙するだけのモードで権限エラーが出なかったとしても、実行役が削除権限を持つことは証明できません。逆に、隔離した複製DBで削除まで試して成功しても、本番の接続先や負荷条件が一致するとは限りません。プレビューでは対象、隔離試験では処理と復元、実行直前には環境と状態の一致を確認する、と証拠の役割を分けます。試験用に外部通知を無効化したなら、本番にも通知がないという結論は出せません。

承認後に対象が変わったら計画へ戻す

承認記録には、誰が、どの環境の、どの計画版を、どの期限まで許可したかを持たせます。操作種別と対象一覧に加え、関連削除や業務停止の見込み、復元試験の結果も判断材料です。「実行してよい」という一言を、後で生成し直した別コマンドへ転用しません。

架空例で承認後にA104が版6へ更新された場合、A101とA104のIDが一致していても、確認したデータと同じ状態とは言えません。実行直前に計画の版と現状を照合し、不一致なら計画を作り直して必要な承認へ戻します。対象の追加だけでなく、削除対象から保全対象への変更も停止条件です。

ただし、確認してから実行するまでに再び変更される可能性があります。そのため、照合と変更を同じトランザクション内で行う、条件付き更新で期待する版を検査する、対象に適切なロックを取るなど、実システムの整合性制御へ接続します。どの方式が必要かは、更新頻度、対象数、許容する待ち時間によって変わります。画面確認を増やすだけでは、この時間差を閉じられません。

実行結果が返らない場合も、同じ承認があるからという理由で削除を再送しません。要求識別子と対象の状態を照会し、実行済み、未実行、処理中、結果不明を区別します。照会不能なら結果不明のまま止め、担当者へ渡す証跡を確保します。

バックアップは作成日時より復元できる範囲を見る

バックアップファイルが存在することと、今回の削除から復旧できることは別の確認です。対象レコードだけでなく、参照される情報、権限、必要な設定が含まれるかを調べ、取得時点から実行時点までの更新をどう扱うか決めます。バックアップ自体にも機密情報が含まれるため、保管先と復元先のアクセスを制限します。

PostgreSQL 18のSQL Dumpは、pg_dumpによるダンプが開始時点のスナップショットを表すこと、単一DBのダンプにクラスタ共通のロール等が含まれないこと、復元時のエラーで部分的な状態になり得ることを説明しています。終了コードやファイルサイズの確認だけでなく、復元先で所有者・権限・必要なデータまで照合する理由がここにあります。

架空例では、削除計画を固めた後、本番から隔離した復元先へバックアップを戻し、A101とA104、保持対象のA102・A103、関連情報を読み取れるか確かめる手順を定めます。この復元試験は計画であり、本記事で実施した結果ではありません。件数が合っても内容が欠ける場合があるので、ID、重要項目、参照関係、アプリケーションからの読取りを照合します。

一つ前の状態へDB全体を戻す方法では、削除後に発生した正当な更新まで失う可能性があります。復元先から必要なデータだけを取り出して戻すのか、サービス全体を過去時点へ戻すのかを分け、競合する新規データや参照整合性を検討します。復元に必要な時間、作業者、容量、鍵や接続情報へのアクセスも、実行前の判断材料にします。

復元試験の記録は「成功」の一語で終えず、バックアップ識別子、取得時刻、復元先、対象版、照合したIDと関連表、失敗した項目、所要時間を残します。所要時間を測っていなければ未計測と記し、業務が許容する停止時間に収まるかは未確認です。取得後の更新を救済する必要がある場合は、その更新履歴を保存できるかも確かめます。復元用の容量不足やアクセス不能が見つかった時点で、本操作の予定を保留します。

継続アーカイブとPITRのような特定時点への復旧も、必要なバックアップとログが揃うことが前提です。この方式に必要な物理バックアップとWALは、pg_dumpの論理ダンプとは別です。両者を組み合わせれば自動的に時点復旧できると考えないでください。削除後に導入すれば過去へ戻れる仕組みではありません。復旧対象、必要な履歴、停止する範囲を具体化できないなら、「バックアップあり」を実行許可の根拠にしないでください。

実行の前後を一つの記録で照合する

実行へ進む順序は、対象と影響の確定、非適用の確認、復元手順の準備と隔離先での試験、確定計画への承認、直前の状態照合、本操作、結果確認とします。バックアップの取得時点や更新停止の位置はシステムに合わせますが、復元試験を本操作の後へ回さないことが判断上の要点です。

確認する状況 期待する判定 次の対応
架空入力からA101・A104の指定版だけを抽出 候補計画は想定と一致 影響範囲と復元条件の確認へ進む
候補が3件となり上限2件を超える 計画作成を停止 条件と入力を調べ、黙って上限を増やさない
承認後にA104の版または保全指定が変わる 承認対象と現状が不一致 再計画し、変更した内容を再承認へ回す
バックアップはあるが隔離復元が未実施 復元可能性は未確認 試験を済ませるまで本操作を保留
操作後の応答が失われる 結果不明 状態照会を行い、重複実行を避ける
削除対象は消えたが保持対象も失われる 影響範囲の違反 後続処理を止め、証跡保全と復旧判断へ回す

削除後は、対象件数だけでなく対象IDの一致と、保持すべきデータの残存を確かめます。関連データ、アプリケーションの読取り、失敗した後続ジョブも対象です。PostgreSQLのDELETEで返る件数やRETURNINGは実際に削除された行の確認に使えますが、外部システムの整合性まで示すものではありません。ゼロ件もそれだけでエラーではないため、予定2件との差を調べます。

復元不能な外部通知、期限を過ぎた業務機会、取り消せない第三者側の処理があるなら、その影響も承認者へ示します。データが戻ることだけを「全て元通り」と表現しません。停止した場合は、実施済みの範囲、未確認の範囲、再開に必要な証拠を記録して引き継ぎます。

実行権限を分け、対象を版付きで固定し、復元を事前に確かめるには運用負担がかかります。運用では、どの担当者が不一致を判断し、何を確かめれば再開できるかまで決めておきます。削除計画の作成、承認、実行、復元の証拠を同じ対象へ結び付けて管理します。

AI操作のロールバックと補償処理の設計は「AI操作のロールバックを設計する:戻せる状態と補償処理を分ける」で解説しています。

出典・参考資料

  1. PostgreSQL Global Development Group「PostgreSQL 18 DELETE」(確認日:2026年10月12日)
  2. PostgreSQL Global Development Group「PostgreSQL 18 EXPLAIN」(確認日:2026年10月12日)
  3. PostgreSQL Global Development Group「PostgreSQL 18 Constraints」(確認日:2026年10月12日)
  4. PostgreSQL Global Development Group「PostgreSQL 18 SQL Dump」(確認日:2026年10月12日)
  5. PostgreSQL Global Development Group「PostgreSQL 18 Continuous Archiving and Point-in-Time Recovery」(確認日:2026年10月12日)
よかったらシェアしてね!
  • URLをコピーしました!

この記事を書いた人

さかっぺのアバター さかっぺ PAP Research運営 / AIガバナンス・アーキテクト / プロンプトデザイナー

ITインフラの実務経験をもとに、AIの安全性と実用性を両立する仕組みを研究。PAP Researchでは、AIモデルの継続観測と、プロンプト・AI技術の実務解説を発信しています。

経歴や研究方法、発信方針は運営者プロフィールで紹介しています。

目次