パッチ適用とホットフィックス
データベースへのパッチ適用やホットフィックスは、多くの場合、本番環境で直接、時間的にクリティカルな変更を行うことを含みます。例えば、実行の遅いクエリの問題を解決するために、本番データベースに直接インデックスを追加する場合があります。
本番データベースに直接パッチを適用すると、スキーマドリフトが発生します。これは、データベーススキーマが信頼できる情報源から「ずれ」、マイグレーション履歴と同期が取れていない状態です。`prisma migrate resolve` コマンドを使用すると、`prisma migrate deploy` でホットフィックスを削除して再適用することなく、マイグレーション履歴を調整できます。
パッチまたはホットフィックスによるマイグレーション履歴の調整
以下のシナリオは、本番環境で手動変更を行い、その変更をマイグレーション履歴や他のデータベースに反映させたい場合を想定しています。
本番環境でのマイグレーション履歴とデータベーススキーマを調整するには
-
本番環境で行った変更をスキーマに反映させます。例えば、特定のモデルに`@@index`を追加します。
-
新しいマイグレーションを生成し、CLIに表示されるタイムスタンプを含む完全なマイグレーション名に注意してください。(
20210316150542_retroactively_add_index
)npx prisma migrate dev --name retroactively-add-index
表示CLI結果migrations/
└─ 20210316150542_retroactively_add_index/
└─ migration.sql
Your database is now in sync with your schema.
✔ Generated Prisma Client (2.19.0-dev.29) to .\node_modules\@prisma\client in 190ms -
マイグレーションを本番環境にプッシュします。ただし、**`migrate deploy` は実行しないでください**。代わりに、前のステップで作成されたマイグレーションを「すでに適用済み」としてマークし、Prisma Migrateがホットフィックスを二度適用しようとしないようにします。
prisma migrate resolve --applied "20201127134938-retroactively-add-index"
このコマンドは、実際のSQLを実行することなく、マイグレーションをマイグレーション履歴テーブルに追加します。
-
パッチが適用された他のデータベースについても、前のステップを繰り返します。例えば、ステージングデータベースにパッチを適用した場合などです。
-
パッチが適用されていない他のデータベースにマイグレーションを伝播させます。例えば、マイグレーションをソース管理にコミットし、CI/CDパイプラインがそれをすべてのデータベースに適用できるようにします。
**注**: `prisma migrate resolve` コマンドによってすでに適用済みとしてマークされたデータベースには、マイグレーションは適用されません。
失敗したマイグレーション
マイグレーションが失敗する可能性があるのは、次の場合です。
- マイグレーションを実行する前に変更し、構文エラーを導入した場合
- すでにデータがあるテーブルに必須の (
NOT NULL
) カラムを追加した場合 - マイグレーションプロセスが予期せず停止した場合
- マイグレーションプロセス中にデータベースがシャットダウンした場合
_prisma_migrations
テーブルの各マイグレーションには、エラーを保存する logs
カラムがあります。
本番環境で失敗したマイグレーションに対処する方法は2つあります
- ロールバックし、任意で問題を修正して再デプロイする
- マイグレーションの手順を手動で完了し、マイグレーションを解決する
オプション1: マイグレーションをロールバック済みとしてマークし、再デプロイする
以下の例は、マイグレーションをロールバックし、任意で問題を修正するための変更を行い、再デプロイする方法を示しています。
-
マイグレーションをロールバック済みとしてマークします。これにより、
_prisma_migrations
テーブル内のマイグレーションレコードが更新され、ロールバック済みとして登録され、再度適用できるようになります。prisma migrate resolve --rolled-back "20201127134938_added_bio_index"
-
マイグレーションが部分的に実行された場合、次のいずれかの方法があります。
- マイグレーションを修正して、あるステップがすでに完了しているかどうかを確認する(例:
CREATE TABLE ... IF NOT EXISTS
)または - 完了したステップを手動で元に戻す(例: 作成されたテーブルを削除する)
マイグレーションを変更する場合は、本番データベースの状態が開発環境に正確に反映されるように、ソース管理にコピーし直してください。
- マイグレーションを修正して、あるステップがすでに完了しているかどうかを確認する(例:
-
関連する場合、失敗したマイグレーションの根本原因を修正します。例えば、SQLスクリプト自体に問題があったためにマイグレーションが失敗した場合などです。変更したマイグレーションは必ずソース管理にコピーし直してください。
-
マイグレーションを再デプロイする
prisma migrate deploy
オプション2: マイグレーションを手動で完了し、適用済みとして解決する
以下の例は、マイグレーションの手順を手動で完了し、そのマイグレーションを適用済みとしてマークする方法を示しています。
-
本番データベース上でマイグレーションの手順を手動で完了します。手動での手順がマイグレーションファイルのステップと正確に一致していることを確認し、変更内容はすべてソース管理にコピーし直してください。
-
マイグレーションを適用済みとして解決します。これにより、Prisma Migrateはマイグレーションが正常に適用されたとみなします。
prisma migrate resolve --applied "20201127134938_my_migration"
失敗したマイグレーションをmigrate diff
とdb execute
で修正する
失敗したマイグレーションの修正を支援するため、Prisma ORMはマイグレーションファイルの作成と実行のための以下のコマンドを提供しています。
prisma migrate diff
は、2つのデータベーススキーマソースを比較し、一方をもう一方の状態にするマイグレーションを作成します。差分の要約またはSQLスクリプトを出力できます。スクリプトは> file_name.sql
でファイルに出力したり、db execute --stdin
コマンドにパイプしたりできます。prisma db execute
は、Prismaマイグレーションテーブルとやり取りすることなく、SQLスクリプトをデータベースに適用します。
これらのコマンドは、バージョン3.9.0
以降ではプレビュー版として(--preview-feature
CLIフラグ付きで)、バージョン3.13.0
以降では一般提供版として利用可能です。
このセクションでは、失敗したマイグレーションのシナリオ例と、migrate diff
およびdb execute
を使用してそれを修正する方法を説明します。
失敗したマイグレーションの例
ローカル開発環境と本番環境の両方のスキーマに、以下のUser
モデルがあるとします。
model User {
id Int @id
name String
}
この時点では、スキーマは同期していますが、2つの環境のデータは異なります。
次に、データモデルを変更し、別のPost
モデルを追加し、User
のname
フィールドを一意にすることにしました。
model User {
id Int @id
name String @unique
email String?
}
model Post {
id Int @id
title String
}
prisma migrate dev -n Unique
コマンドで「Unique」というマイグレーションを作成し、それがローカルのマイグレーション履歴に保存されます。開発環境ではマイグレーションの適用に成功し、いよいよ本番環境にリリースする時が来ました。
残念ながら、このマイグレーションは部分的にしか実行できません。Post
モデルの作成とemail
カラムの追加は成功しましたが、name
フィールドを一意にすることが次のエラーで失敗しました。
ERROR 1062 (23000): Duplicate entry 'paul' for key 'User_name_key'
これは、本番データベースに一意でないデータ(例: 同じ名前のユーザーが2人)が存在するためです。
これで、部分的に実行されたマイグレーションから手動で復旧する必要があります。失敗した状態から復旧するまで、prisma migrate deploy
を使用したさらなるマイグレーションは不可能です。
この時点で、一意でないデータをどうするかによって、2つの選択肢があります。
- 一意でないデータが有効であり、現在の開発作業を進められないと判断します。完全なマイグレーションをロールバックしたい場合、変更を元に戻すを参照してください。
- データベース内に一意でないデータが存在するのが意図的ではなく、それを修正したい場合。修正後、マイグレーションの残りの部分を進めたい場合、不足している変更を適用するを参照してください。
変更を元に戻す
この場合、本番データベースを最後のマイグレーション前のデータモデルの状態に戻すマイグレーションを作成する必要があります。
-
まず、失敗したマイグレーション前の時点でのマイグレーション履歴が必要です。これはGit履歴から取得するか、ローカルのマイグレーション履歴にある最後の失敗したマイグレーションのフォルダを削除することで得られます。
-
これで、本番環境の現在の失敗した状態から、ローカルのマイグレーション履歴で指定された状態に戻したいとします。
-
以下の
prisma migrate diff
コマンドを実行します。npx prisma migrate diff \
--from-url "$DATABASE_URL_PROD" \
--to-migrations ./prisma/migrations \
--shadow-database-url $SHADOW_DATABASE_URL \
--script > backward.sqlこれにより、本番環境の現在の失敗した状態から、マイグレーション履歴で定義されたターゲット状態にするために必要なすべての変更を含むSQLスクリプトファイルが作成されます。
--to-migrations
を使用しているため、このコマンドにはシャドウデータベースが必要であることに注意してください。 -
以下の
prisma db execute
コマンドを実行します。npx prisma db execute --url "$DATABASE_URL_PROD" --file backward.sql
これは、マイグレーションテーブルとやり取りすることなく、SQLスクリプト内の変更をターゲットデータベースに適用します。
-
以下の
prisma migrate resolve
コマンドを実行します。npx prisma migrate resolve --rolled-back Unique
これにより、本番環境のマイグレーションテーブルにある「Unique」という失敗したマイグレーションがロールバック済みとしてマークされます。
-
これで、ローカルのマイグレーション履歴は本番データベースの状態と同じ結果をもたらします。これで、作業中の機能(一意でない名前を持つ)に関する新しい理解に合ったマイグレーションを作成するために、再度データモデルを変更できます。
不足している変更を適用する
この場合、一意でないデータを修正し、計画通りに残りのマイグレーションを進める必要があります。
-
マイグレーションを本番環境にデプロイしようとした際のエラーメッセージで、すでに
name
カラムに重複データがあることが示されていました。問題のある行を変更または削除する必要があります。 -
失敗したマイグレーションの残りの部分を適用し続け、
schema.prisma
ファイルで定義されたデータモデルに到達させます。-
以下の
prisma migrate diff
コマンドを実行します。
npx prisma migrate diff --from-url "$DATABASE_URL_PROD" --to-schema-datamodel schema.prisma --script > forward.sqlこれにより、本番環境の現在の失敗した状態から、
schema.prisma
ファイルで定義されたターゲット状態にするために必要なすべての変更を含むSQLスクリプトファイルが作成されます。 -
以下の
prisma db execute
コマンドを実行します。npx prisma db execute --url "$DATABASE_URL_PROD" --file forward.sql
これは、マイグレーションテーブルとやり取りすることなく、SQLスクリプト内の変更をターゲットデータベースに適用します。
-
以下の
prisma migrate resolve
コマンドを実行します。npx prisma migrate resolve --applied Unique
これにより、本番環境のマイグレーションテーブルにある「Unique」という失敗したマイグレーションが適用済みとしてマークされます。
-
これで、ローカルのマイグレーション履歴は本番環境の状態と同じ結果をもたらします。これで、すでに知られているmigrate dev
/migrate deploy
ワークフローを引き続き使用できます。
マイグレーション履歴の競合
これはバージョン3.12.0以降には適用されません。
prisma migrate deploy
は、すでに適用されたマイグレーションが編集されている場合に警告を発しますが、マイグレーションプロセスを停止させません。警告を削除するには、元のマイグレーションをソース管理から復元してください。
Prisma MigrateとPgBouncer
PgBouncerを接続プールに使用している環境でPrisma Migrateコマンドを実行しようとすると、以下のエラーが表示される場合があります。
Error: undefined: Database error
Error querying the database: db error: ERROR: prepared statement "s0" already exists
詳細情報と回避策については、Prisma MigrateとPgBouncerの回避策を参照してください。更新情報については、GitHub issue #6485をフォローしてください。