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