🚀

PostgreSQL --data-onlyの落とし穴 - 安全なデータ差し替え方法

に公開

はじめに

新規アプリ開発のデータベースに Aurora Serverless v2 for PostgreSQL を利用しています。
普段はRDSが自動で毎日スナップショットを取ってくれていますが、特定のリリース前には手動でバックアップを取得する必要があります。

Aurora PostgreSQLはBacktrackに対応していないため、リリース直前の状態に戻したい場合は、スナップショット復元か、pg_dumpによるバックアップが選択肢になります。

「スナップショット復元すれば良いのでは?」
と思うかもしれませんが、Auroraのスナップショット復元は新しいクラスターの作成が必要で、起動まで時間がかかるため、すぐに戻せる手段としてpg_dumpでのバックアップを選びました。


検証したバックアップ & リストア手順

フルバックアップの場合

以下のようにコマンドを実行します。

# バックアップ
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT -Fc > $DUMP_FILENAME

# リストア
pg_restore -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT --clean --if-exists dump_file.dump

この方法ではスキーマも含めて全てバックアップでき、--cleanで既存オブジェクトを削除してからリストアするため、既存データがあっても問題なく復元できます。


罠:--data-onlyオプション

今回、「データだけを差し替えたい」という要件がありました。
PostgreSQLにはpg_dump--data-onlyオプションがあり、説明は以下の通りです。

データのみをダンプし、スキーマ(データ定義)はダンプしません。
テーブルデータ、ラージオブジェクト、シーケンス値がダンプされます。
公式ドキュメント

「これだ!」と思って実行してみました。

pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT -Fc --data-only > $DUMP_FILENAME

リストア時はこうです。

pg_restore -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT $DUMP_FILENAME

しかし、復元時にこんなエラーが...

ERROR:  duplicate key value violates unique constraint "xxxx_pkey"

つまり、既存データと同じ主キーを持つ行がすでに存在していたのです。


なぜ起きたのか

--data-only既存データを削除してくれません
既存テーブルに同じキーの行があると、当然「キー重複」エラーになります。

「じゃあ--cleanを付ければ消してくれるのでは?」と思うかもしれませんが、pg_restore--data-only--cleanを同時に指定できません。

つまり、--data-onlyは以下のような用途でしか実用的ではありません。

  • データベースが空(スキーマだけ存在)
  • 初期データ投入

本番DBのように既にデータが入っている環境では、事前に全テーブルのデータを削除するSQLを実行しないと復元できません


実運用での結論

結局、以下のような方針になりました。

  • データだけ差し替えたい場合でも、フルダンプ & フルリストアが安全
  • コマンドは以下の通り
# バックアップ
pg_dump -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT -Fc > $DUMP_FILENAME

# リストア
pg_restore -h $DB_HOST -U $DB_USER -d $DB_NAME -p $DB_PORT --clean --if-exists dump_file.dump

これなら、スキーマ変更がなくても既存データが確実に置き換わります。


まとめ

  • --data-only既存データを消さない
  • --data-only--clean併用不可
  • 実運用で安全なのはスキーマごとフルダンプ

もしどうしてもデータだけ入れ替えたい場合は、事前に全テーブルを空にするSQLを流す必要があります。
とはいえ、作業の安全性や工数を考えると、フルダンプの方がトラブルを避けやすいです。


最後に

Aurora Serverless v2のようにスナップショット復元が遅い環境では、pg_dumpによるフルバックアップが即時復元の強い味方になります。
一見便利そうに見える--data-onlyですが、運用環境で安易に使うとトラブルにつながるため注意が必要です。

Discussion