パッチとホットフィックス
データベースのパッチまたはホットフィックスは、多くの場合、時間的に重要な変更を本番環境で直接行うことを伴います。たとえば、実行速度の遅いクエリの問題を解決するために、本番データベースにインデックスを直接追加する場合があります。
本番データベースを直接パッチ適用すると、スキーマドリフトが発生します。データベーススキーマが真実の情報源から「ドリフト」し、マイグレーション履歴と同期しなくなります。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がホットフィックスを2回目に適用しようとしないようにします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に従ってください。