3行まとめ
追加。
補完。
削除。
復旧。
DB migrationは、1つの差分ではなく段階を分けた運用です。
- CodexにDB migrationを任せる時は、migration fileだけでなく、expand/contract、lock、backfill、deploy順序、rollback、ownerを先に決めます。
- schema変更とdata変更を同じ差分へ詰め込むと、本番で戻しにくくなります。追加、両対応、補完、切替、削除へ段階化します。
- PostgreSQLの
ALTER TABLEやPrisma Migrateのshadow database、schema driftの考え方を踏まえ、Codexには「書くSQL」だけでなく「確認する条件」も渡します。
CodexにDB migrationを頼むと、migration fileやORM schemaの差分はすぐ作れます。columnを追加する。名前を変える。NOT NULLを足す。indexを作る。古いcolumnを消す。小さな差分なら、PR上ではとても自然に見えます。
ただ、DB migrationはコード差分と違います。deploy後に本番データが変わります。長いlockが発生することがあります。backfillが途中で止まることがあります。rollbackしてもdataは戻らないことがあります。古いapp versionと新しいapp versionが同時に動く時間もあります。
この記事では、CodexにDB migrationを任せる前に、依頼文へ入れるべき条件を整理します。コード全体の移行は公開済みのCodexにコード移行を任せる前に決めることで扱いました。ここでは、schema変更とdata変更に絞ります。
この記事でわかること
影響。
変換。
順序。
判断。
schema変更、data変更、deploy順序を分けるとreviewが楽になります。
- DB migrationをCodexへ頼む前に決める7項目
- expand/contractで破壊的変更を後ろへ送る考え方
- PostgreSQLの
ALTER TABLEでlockやscanを気にする理由 - Prisma Migrateのshadow database、schema driftをどう見るか
- backfillをmigration fileのついでにしない設計
- rollbackとroll-forwardを事前に分ける方法
- Codexへそのまま渡せる依頼packet
- reviewで止めるべきmigration差分
この記事は、特定DBの完全な運用手順ではありません。PostgreSQL、MySQL、SQLite、MongoDB、Prisma、Rails、Django、Flyway、Liquibaseなどで詳細は変わります。実際のSQL、lock、index作成、transaction、replication、backup、restoreは、利用中のDBとmigration toolの公式Docsで確認してください。
前提知識
| 項目 | 内容 | 見方 |
|---|---|---|
| PostgreSQL | ALTER。 | |
| Prisma | migrate。 | |
| Shadow DB | drift。 | |
| Production | deploy。 |
migrationはORMの機能だけでなく、DB側のlockやscanも見ます。
DB migrationは、source codeとdatabase stateの両方に影響します。PRで見えるのはmigration fileやschema fileですが、本番で起きるのはtable定義の変更、data変換、index作成、constraint検証、lock、replication遅延、application compatibilityです。
PostgreSQLのALTER TABLE Docsでは、subcommandごとに必要なlock levelが変わり、明示がない場合はACCESS EXCLUSIVE lockが取得されることが説明されています。また、SET NOT NULLでは既存行の確認が必要になる場合があります。Prisma Migrateでは、developmentでshadow databaseを使い、migration historyからschema driftやdata lossの可能性を検出する考え方が説明されています。
migrationはコード差分より戻しにくい
コードは前のversionへ戻せます。しかし、DBに入ったdata変更、dropしたcolumn、変換済み値、失敗途中のbackfillは、単純なgit revertでは戻りません。
そのため、Codexへは「migration fileを作って」ではなく、「どの順序で安全に変えるかを設計して」と頼みます。
dev commandとproduction commandを分ける
development用のcommandとproduction用のcommandを混同しないことも重要です。Prismaではmigrate dev、migrate deploy、migrate reset、migrate resolveのように用途が分かれています。developmentで便利なresetは、本番では破壊的です。
Codexへは、実行してよいcommand、実行してはいけないcommand、dry-runやdiffだけ許可するcommandを明示します。
migration前に決める7項目
| 項目 | 内容 | 見方 |
|---|---|---|
| Change | 変更。 | |
| Data | 変換。 | |
| Lock | 影響。 | |
| Backfill | 補完。 | |
| Deploy | 順序。 | |
| Rollback | 復旧。 | |
| Owner | 承認。 |
未定のままmigration fileを書くと、本番で判断することになります。
DB migrationを頼む前に、7項目を決めます。
| 項目 | 決めること | 曖昧なまま起きること |
|---|---|---|
| 変更 | add、rename、drop、constraint、index | 破壊的変更が混ざる |
| data | backfill、変換、削除 | rollback不能になる |
| lock | table lock、scan、rewrite | 本番trafficを止める |
| deploy | appとDBの順序 | 古いappが壊れる |
| rollback | 戻すか進めるか | 障害時に迷う |
| verify | 件数、constraint、query | 成功判定が曖昧 |
| owner | 承認者と実行者 | 本番判断が宙に浮く |
CodexはSQLやORM schemaを作れますが、本番の停止許容時間、backup方針、メンテナンス窓、replica、traffic量、障害時の判断者は知りません。ここは人間が渡す必要があります。
schema変更とdata変更を分ける
schema変更は、tableやcolumnやindexやconstraintを変える作業です。data変更は、既存行を埋める、値を変換する、重複を解消する、古い値を削除する作業です。
同じPRに入っていても、実行タイミングは分けます。schemaを先に足し、appを両対応にし、backfillし、確認してからconstraintやdropへ進みます。
ownerを決める
DB migrationにはownerが必要です。migration作成者、reviewer、実行者、障害時の判断者を分けます。Codexが作った差分でも、実行判断は人間が持ちます。
reviewで見ること
reviewでは、migration fileのSQLだけでなく、deploy順序、data影響、rollback/roll-forward、確認query、実行時間の見積もり、large tableの扱いを見ます。
expand/contractで小さく進める
- 1Add
追加。
- 2Dual
両対応。
- 3Backfill
補完。
- 4Switch
切替。
- 5Drop
削除。
破壊的変更を後ろへ送ると、deployとrollbackの余地が残ります。
DB migrationは、expand/contractで小さく進めると安全になります。
expand: 新しいcolumnやtableを追加する
dual: 古いschemaと新しいschemaの両方に対応する
backfill: 既存dataを新しいschemaへ補完する
switch: read/writeの参照先を切り替える
contract: 古いcolumnや古い処理を削除する
この流れにすると、古いapp versionと新しいapp versionが同時に動いても壊れにくくなります。
addから始める
最初は追加から始めます。新しいnullable column、新しいtable、新しいindex、新しいwrite pathなどです。既存のread/writeを壊さない変更なら、rollbackの余地が残ります。
removeは最後にする
drop column、rename、NOT NULL追加、constraint追加、古いfield削除は最後に回します。特にdropは戻しにくいです。使われていないことをログ、query、コード検索、feature flag、dashboardで確認してから行います。
評価基準
古いapp versionでも、新しいapp versionでも、migrationの途中状態で動くなら良い進め方です。途中状態を許容できないmigrationは、deploy窓や停止手順が必要です。
lockとtable rewriteを見る
| 項目 | 内容 | 見方 |
|---|---|---|
| Lock | 待ち。 | |
| Scan | 確認。 | |
| Rewrite | 書換。 | |
| Index | 作成。 |
migration reviewではSQLの見た目だけでなく、DBが何をするかを見ます。
DB migrationのreviewでは、SQLの見た目だけでなく、DBが何をするかを見ます。
PostgreSQLのALTER TABLEは、subcommandごとにlockやscanの影響が違います。SET NOT NULLでは既存行の確認が必要になる場合があります。column追加、default、constraint、index作成、type変更は、table sizeやDB versionによって影響が変わります。
ALTER TABLEの影響を読む
Codexへは、対象DBの公式Docsを読ませた上で、migrationごとに次を説明させます。
- lockが強い操作か
- table scanが必要か
- table rewriteが起きる可能性があるか
- transaction内で実行できるか
- long-running queryやwrite trafficに影響するか
- replicaやbackupに影響するか
large tableを別扱いにする
小さなtableなら一瞬で終わるmigrationでも、large tableでは長時間のlockやI/Oが発生することがあります。行数、サイズ、write頻度、index数、FK、trigger、replicationを見ます。
large tableでは、online migration、concurrent index、chunked backfill、maintenance window、traffic制御を検討します。
backfillをjobとして扱う
- Plan
範囲。
- Chunk
分割。
- Run
実行。
- Resume
再開。
- Verify
確認。
backfillはmigration fileのついでではなく、再開できるjobとして扱います。
backfillは、migration fileのついでに書くものではなく、jobとして扱います。
たとえば、新しいnormalized_email columnを追加する場合、既存user全件を更新する必要があります。これを1つのmigration transactionで全件更新すると、lock、WAL、replication、timeout、rollbackの問題が出ます。
chunkとresumeを入れる
backfillはchunkに分けます。ID範囲、created_at範囲、pagination、limitで分割し、途中で止まっても再開できるようにします。
1回のjobで最大1000件だけ更新する。
最後に処理したIDを記録する。
既に埋まっている行はskipする。
失敗時は同じchunkを再実行しても壊れない。
このような条件をCodexへ渡します。
進捗を記録する
backfillには進捗が必要です。対象件数、完了件数、残件数、失敗件数、再試行回数、処理時間、最後のerrorを記録します。
注意点
backfill中に新しいwriteが発生する場合、dual writeやread fallbackが必要になることがあります。migration単体で完結させず、app codeと一緒に設計します。
rollbackとroll-forwardを決める
- 1Stop
停止。
- 2Assess
判断。
- 3Rollback
戻す。
- 4Forward
進める。
- 5Verify
確認。
dataを変えた後は、schema rollbackだけでは戻らないことがあります。
DB migrationでは、rollbackだけが正解とは限りません。dataが変わった後は、schemaだけ戻してもアプリが正しく動かないことがあります。
事前に、どの失敗ならrollbackするか、どの失敗ならroll-forwardするかを決めます。
| 状態 | 対応 | 理由 |
|---|---|---|
| migration未実行 | deploy停止 | 影響前 |
| schema追加のみ | app rollback可能 | 追加は残せる |
| backfill途中 | job停止と再開 | dataは途中状態 |
| constraint失敗 | data修正後に再実行 | 原因がdata |
| drop後に障害 | backup/restore検討 | schema rollbackだけでは不足 |
schema rollbackだけで戻らない
drop column後にコードを戻しても、古いコードが読むcolumnはありません。data変換後に型を戻しても、元の値は失われているかもしれません。
そのため、破壊的変更は最後にし、backup、restore、roll-forward patch、feature flag、read fallbackを用意します。
deploy順序を固定する
DB migrationとapp deployの順序は固定します。
1. 新schemaを追加する
2. appを両対応にする
3. 新writeを有効にする
4. backfillする
5. readを切り替える
6. 古いschemaを削除する
Codexへは、この順序から外れる差分を作らないよう指示します。
Codexへ渡す依頼packet
| 項目 | 内容 | 見方 |
|---|---|---|
| Goal | 目的。 | |
| SQL | 変更。 | |
| Risk | 影響。 | |
| Tests | 確認。 | |
| Ops | 運用。 |
packet化すると、Codexが書くmigrationと人間のreview観点が揃います。
Codexへは、次のようなpacketで渡します。
目的:
users.email を正規化した normalized_email columnへ移行する。
DB:
PostgreSQL。large tableのため、長時間lockを避ける。
許可する変更:
nullable columnの追加。
app codeのdual write。
chunked backfill job。
確認query。
禁止:
既存columnのdrop。
いきなりNOT NULLを付ける。
migration transaction内の全件UPDATE。
productionでreset系commandを実行する。
deploy順序:
add column -> dual write -> backfill -> verify -> read switch -> NOT NULL検討 -> old path削除。
backfill:
1000件ずつ処理する。
再実行しても安全にする。
進捗と失敗件数をlogへ残す。
review:
lock、scan、rewrite、rollback、確認query、ownerをPR本文に書く。
このpacketがあると、Codexがmigration fileだけを作って終わることを避けられます。
よくある失敗
先に削除。
未補完。
長時間。
判断なし。
DB migrationの事故は、短いSQLの裏側にある運用未定義から起きます。
renameを1回で済ませる
column renameは、古いapp versionが残っていると壊れます。新column追加、dual write、read切替、古いcolumn削除に分けるほうが安全です。
NOT NULLを先に付ける
既存行にNULLがある状態でNOT NULLを付けると失敗します。先にbackfillし、確認queryでNULLがないことを見てからconstraintを追加します。
migration内で全件UPDATEする
全件UPDATEは、table size次第で長時間かかります。lock、WAL、replication、timeoutの影響があります。chunked jobへ分けます。
drop columnを同じPRで入れる
新しいschemaへ切り替えた直後に古いcolumnをdropすると、rollbackの余地がなくなります。観測期間を置き、古いpathが使われていないことを確認してから削除します。
driftを見ない
手動変更やbranch切替でmigration historyとDB schemaがズレることがあります。Prisma MigrateのDocsでは、shadow databaseを使ったdrift検出が説明されています。migration toolの警告を無視しないことが大事です。
FAQ
| 項目 | 内容 | 見方 |
|---|---|---|
| Rename? | 段階。 | |
| NOT NULL? | 補完。 | |
| Drop? | 最後。 | |
| Rollback? | 事前。 |
迷ったら、古いコードと新しいコードが同時に動く時間を想像します。
Codexにmigration fileを書かせてもよいですか
書かせてもよいですが、実行判断は別です。Codexにはmigrationの意図、危険な操作、確認query、rollback/roll-forward条件を書かせ、人間がreviewします。
column renameはどう扱いますか
本番では、renameを1回で終わらせるより、新column追加、dual write、backfill、read切替、old column削除へ分けるほうが安全です。
rollback scriptも作るべきですか
作れる場合は作ります。ただし、data変換後は完全なrollbackができないことがあります。rollbackできる範囲とroll-forwardする条件を分けます。
Prismaのshadow databaseは本番にも必要ですか
PrismaのDocsでは、shadow databaseは主にdevelopmentでmigration historyからdriftやdata lossの可能性を検出するために使われ、本番向けcommandでは使われないことが説明されています。導入時は利用中のPrisma versionとcommandを確認してください。
migration reviewで最初に見るものは何ですか
drop、rename、NOT NULL、全件UPDATE、index作成、type変更、constraint追加、reset系commandを先に見ます。次にdeploy順序、backfill、rollback、確認query、ownerを見ます。
次に読むなら
参照した主な情報源
- PostgreSQL Documentation: ALTER TABLE
- PostgreSQL Documentation: Modifying Tables
- Prisma Documentation: About the shadow database
- Prisma Documentation: Development and production
- Prisma Documentation: Prisma Migrate CLI
更新履歴
- 2026.06.01
初版。
DBやORMのmigration仕様は変わるため、導入時に公式Docsを確認します。
- 2026.06.01: 初版公開。CodexへDB migrationを任せる前のexpand/contract、lock、backfill、rollbackを整理しました。
