要点: 安全な変更では、古いアプリケーションと新しいアプリケーションが一定時間共存すると考えます。
この記事の用語: Expand–Contract:新構造を追加して移行後に旧構造を削除する手順。Backfill:過去データを新構造へ補う処理。
現場の課題
列名の変更や厳しい制約を一度に入れると旧版が停止します。大きな更新は長時間ロックを保持するため、変更を戻せる小さな段階へ分ける必要があります。
デプロイ中は旧版と新版が共存します。Expand–Contractは、追加、互換書き込み、Backfill、読み取り切替、旧構造削除へ分け、各段階を戻せるようにします。
設計と実装
- 現行動作を変えずに、NULL許容列または新テーブルを追加します。
- 旧版と新版の両方で動くコードをデプロイし、再開可能なバッチでBackfillします。
- フィーチャーフラグで読み取りを切り替え、ロールバック不要を確認した後のリリースで旧構造を削除します。
実装例
lastId = checkpoint.load('account_region_v2')
rows = SELECT id FROM accounts WHERE id > :lastId ORDER BY id LIMIT 1000
UPDATE accounts SET region_v2 = derive(region) WHERE id IN (:rows)
checkpoint.save(MAX(rows.id))
sleep(rateLimit)本番導入の進め方
Expand、互換アプリケーション、Backfill、切替、Contractを別リリースにします。少数テナントから読み取りを切り替え、ロールバック期間と監査結果を確認してから旧構造を削除します。
まとめ
無停止マイグレーションは、賢いSQL一文ではなく、互換性があり戻せる変更の連続です。
