先に結論
データベースマイグレーションとは、データベースの構造や中身を新しい状態へ移行する作業です。
アプリケーション開発では、特にテーブル追加、カラム追加、型変更、制約変更、既存データの変換といった変更を指すことが多くあります。
- コードのデプロイと違い、データそのものやスキーマを変える
- 本番ではロック、処理時間、互換性、戻しにくさが問題になりやすい
migration を流すだけで安全になるわけではない- 旧版と新版が短時間でも共存するなら、互換性を先に考える必要がある
- 大きな変更では expand and contract のような段階移行が有効になる
要するに、データベースマイグレーションは便利な自動化手段ですが、本番ではアプリ変更以上に慎重さが要る作業です。
データベースマイグレーションとは
データベースマイグレーションは、データベースの状態を変更するための手順をコードやSQLとして管理し、環境ごとに同じ変更を再現できるようにする考え方です。
Laravel では migration ファイルでテーブル作成やカラム追加を管理し、php artisan migrate のような形で適用します。
Prisma など他のツールでも、スキーマ変更を履歴として管理し、本番やステージングへ順に反映する流れは共通しています。
ここでいうマイグレーションには、大きく2種類あります。
| 種類 | 例 |
|---|---|
| スキーマ変更 | テーブル追加、カラム追加、型変更、制約追加、インデックス追加 |
| データ移行 | 既存データの変換、値の再計算、列のコピー、NULL埋め、分割統合 |
初心者は migration = テーブルを作るもの と捉えがちですが、実務ではデータ移行まで含めて考えないと危険です。
なぜ本番反映で注意が必要なのか
ローカルや開発環境では一瞬で終わる変更でも、本番では話が変わります。
理由は、データ量、同時接続、外部連携、ユーザー操作が絡むからです。
1. テーブルロックや待ちが発生することがある
MySQL の Online DDL や PostgreSQL の ALTER TABLE には、できるだけロックを減らす仕組みがあります。
ただし、ロックがゼロになる とは限りません。変更内容によっては、短時間でも強いロックが必要になったり、大きなテーブルでは待ち時間が伸びたりします。
本番では、この短い待ちでもAPI遅延、タイムアウト、ジョブ詰まりにつながることがあります。
特に、巨大テーブルへの ALTER TABLE、インデックス追加、制約追加は、事前検証なしで流すと危険です。
2. 旧版アプリと新版アプリの互換性が崩れる
アプリのリリース中は、旧版と新版が同時に動くことがあります。
この状態で、旧版が読むカラムを先に消す、必須制約を先に強くする、型を互換性なく変える、といった変更を入れると、アプリ側がすぐ壊れます。
そのため、本番では DBだけ先に変えても旧版が動くか、新版がまだ新カラム未使用でも問題ないか を見る必要があります。
この観点を無視すると、アプリの再ロールバックだけでは復旧できないことがあります。
3. 戻しにくい変更がある
カラム追加は比較的戻しやすくても、データ削除、型変換、列統合、既存値の上書きは簡単に戻せません。
本番ではユーザー操作や外部連携が進むため、コードを戻してもデータ状態は元に戻らないことがあります。
このため、障害時に単純なロールバックが効きにくく、ロールフォワードとは?戻すのではなく次の修正で進める考え方 のような対応が必要になることもあります。
4. 実行時間が読みにくい
同じ migration でも、開発DBと本番DBではデータ件数が違います。
数百件では一瞬でも、数千万件では数分から数時間かかることがあります。
さらに、トラフィックの多い時間帯に実行すると、普段見えない待ちや競合が起きやすくなります。
だから、本番反映の時間帯や変更凍結との関係まで含めて考える必要があります。
よくある危ない変更
本番で特に注意したいのは、次のような変更です。
- 大きなテーブルへの
ALTER TABLE NOT NULL制約の追加- 既存カラムの型変更
- カラム名変更
- カラム削除
- 大量データの一括更新
- インデックス追加や再作成
- 外部キーや一意制約の追加
これらは 書ける ことと 安全に本番へ流せる ことが別です。
開発環境で通ったから本番も安全、とは考えない方がよいです。
expand and contract とは
本番向けの安全策として有名なのが、expand and contract という考え方です。
Prisma の公式ドキュメントでも、データ移行でこの方法が紹介されています。
ざっくり言うと、次の順番で進めます。
- 新しいカラムやテーブルを追加する
- 旧構造と新構造の両方へ書けるようにする
- 既存データを新構造へコピー・変換する
- 読み取り先を新構造へ切り替える
- 問題がないことを確認する
- 旧構造を削除する
この方法の利点は、旧版アプリと新版アプリが共存しやすいことです。
いきなり 列名を変えて終わり にするより、本番ではかなり安全です。
実務でどう進めると安全か
本番でデータベースマイグレーションを行うなら、少なくとも次の流れを意識すると事故が減ります。
1. 変更の種類を分ける
スキーマ変更なのか、データ移行なのか、両方なのかを分けます。
特にデータ移行は、migration ファイル1本に押し込まず、別バッチや段階処理に分けた方が安全なことがあります。
2. 互換性を先に確認する
旧版アプリが動く状態を保てるかを見ます。
先に削除しない 先に必須にしない 新旧両対応期間を作る という発想が大事です。
3. 実行時間を見積もる
本番相当データ量で検証し、何分かかるか、ロックは出るか、CPUやIOはどれくらい使うかを確認します。
可能なら、ステージングで件数を近づけて試した方がよいです。
4. 戻し方を決める
戻せる変更なのか、戻せない変更なのかを最初に決めます。
戻せないなら、どこで停止するか、どう前へ進めるかまで考えておく必要があります。
5. アプリ反映と順序を合わせる
コード反映とDB変更の順番がずれると壊れます。
この点は、デプロイとリリースの違いとは?本番反映と公開を分けて整理 の考え方とも相性がよく、DB変更を先に入れるか 機能公開は後にするか を分けて考えると整理しやすいです。
Laravelで誤解しやすいこと
Laravel の migration は便利ですが、便利さのせいで誤解も起きやすいです。
migration がある = 本番で安全
違います。
migration は履歴管理と再現性を助けますが、ロック、処理時間、互換性までは自動で解決してくれません。
rollback が書いてあれば安心
down() が書いてあっても、実データを元通りにできるとは限りません。
特に、値変換や削除を含む migration では、コード上の rollback と業務上の復旧は別です。
何でも migration に入れればよい
大量データ更新や長時間処理まで migration に詰め込むと、本番で扱いづらくなります。
スキーマ変更とデータ移行を分ける方が安全な場面は多いです。
まとめ
データベースマイグレーションとは、データベースの構造や中身を新しい状態へ移行する作業です。
開発では日常的でも、本番ではロック、実行時間、互換性、戻しにくさがあるため、かなり注意が必要です。
とくに本番では、migration が通るか より、ユーザー影響なく終わるか を見るべきです。
旧版との互換性を保ち、変更を小さく分け、戻せない変更は前提から設計し、必要なら expand and contract のような段階移行を使うと安全性が上がります。