メインコンテンツへ移動
JA
ホーム / 技術ブログ / Expand–ContractでDBを無停止変更する
2026年7月04日 · Z-SOFT Admin · 読了目安 5 分

Expand–ContractでDBを無停止変更する

旧版と新版が同時に動ける互換手順で、DBスキーマを無停止変更します。

記事一覧へ戻る

要点: 安全な変更では、古いアプリケーションと新しいアプリケーションが一定時間共存すると考えます。

この記事の用語: Expand–Contract:新構造を追加して移行後に旧構造を削除する手順。Backfill:過去データを新構造へ補う処理。

現場の課題

列名の変更や厳しい制約を一度に入れると旧版が停止します。大きな更新は長時間ロックを保持するため、変更を戻せる小さな段階へ分ける必要があります。

単純な対策だけでは不十分な理由

デプロイ中は旧版と新版が共存します。Expand–Contractは、追加、互換書き込み、Backfill、読み取り切替、旧構造削除へ分け、各段階を戻せるようにします。

処理フロー

Expand
互換スキーマ追加
Migrate
Dual 読み取り・書き込み
Verify
Backfillと照合
Contract
旧経路削除
互換性を先に追加し、旧経路が不要と証明してから削除します。

アーキテクチャ上の判断

Additive Expand

RenameはAdd、Copy、切替、Removeに分解します。

再開可能Backfill

安定キー Range、小Commit、Checkpointを使います。

制約を別途Validate

失敗扱いingを抑えて既存Rowを検証します。

さらに深く考える

ロールバックはデータ問題

新形式だけのデータがある間はReverse Compatibilityを維持します。

制約で保証

照合後にDB 制約で前提を強制します。

実装手順

  1. 現行動作を変えずに、NULL許容列または新テーブルを追加します。
  2. 旧版と新版の両方で動くコードをデプロイし、再開可能なバッチでBackfillします。
  3. フィーチャーフラグで読み取りを切り替え、ロールバック不要を確認した後のリリースで旧構造を削除します。

コード例: 再開可能なPrimary-キー 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)

各バッチ後にレプリカ遅延とLock Waitを監視し、顧客影響前に自動停止します。

想定しておく障害

  • 旧ワーカーがLegacy Fieldだけを書きます。
  • Backfillが新しいOnline 書き込みを上書きします。
  • 旧Column削除がレポートを壊します。

監視すべきこと

指標何が分かるか
旧・新読み取り/書き込み数Compatibility利用を確認します。
Backfill進捗・Mismatch完全性と変換精度です。
Lock Wait・レプリカ Lag顧客トラフィックを保護します。

設計の検証方法

  • 旧・新バージョンを同時実行します。
  • 任意CheckpointでBackfillを再開します。
  • 同時Updateを上書きしないか確認します。

本番導入の進め方

Expand、互換アプリケーション、Backfill、切替、Contractを別リリースにします。少数テナントから読み取りを切り替え、ロールバック期間と監査結果を確認してから旧構造を削除します。

本番前チェックリスト

  • 実Volume相当でDDL Lockを確認します。
  • Backfillにレート制限、Checkpoint、一時停止を持たせます。
  • 旧経路Usageゼロを確認してContractします。

まとめ

無停止マイグレーションは、賢いSQL一文ではなく、互換性があり戻せる変更の連続です。

Z-SOFTとの協業

今日のテクノロジーに関する一つひとつの判断が、その後の何年にも影響を与えます。

現状を評価し、目標を明確にし、企業の成長方針に合ったアーキテクチャを選定するために、Z-SOFTのチームにご相談ください。

相談を予約する