PlanetScale
PrismaとPlanetScaleは、PrismaのORMとPlanetScaleのスケーラブルなMySQLベースのプラットフォームを活用し、データアクセスアプリケーションの高速かつ型安全な開発を最適化する開発環境を提供します。
このドキュメントでは、Prisma ORMとPlanetScaleを使用する際の概念について説明し、PlanetScaleと他のデータベースプロバイダーとの共通点および相違点を解説し、PlanetScaleと統合するためのアプリケーション設定プロセスを案内します。
PlanetScaleとは?
PlanetScaleは、Vitessデータベースクラスタリングシステムを使用して、MySQL互換のデータベースプラットフォームを提供します。主な機能は以下の通りです。
- エンタープライズレベルのスケーラビリティ。PlanetScaleは、複数のデータベースサーバーにわたるスケーリングをサポートする、高可用性プロダクションデータベースクラスターを提供します。これは、接続制限の管理という問題を回避できるため、サーバーレス環境で特に役立ちます。
- データベースブランチ。PlanetScaleでは、データベーススキーマのブランチを作成できるため、開発ブランチで変更をテストしてから本番データベースに適用できます。
- ノンブロッキングスキーマ変更のサポート。PlanetScaleは、データベースをロックしたり、ダウンタイムを引き起こしたりすることなく、ユーザーがデータベーススキーマを更新できるワークフローを提供します。
他のデータベースプロバイダーとの共通点
Prisma ORMをPlanetScaleと組み合わせて使用する際の多くの側面は、他のリレーショナルデータベースでPrisma ORMを使用する場合とまったく同じです。引き続き以下のことができます。
- データベースをPrismaスキーマ言語でモデル化する
- スキーマでPrisma ORMの既存の
mysql
データベースコネクタを使用し、PlanetScaleが提供する接続文字列も使用する - PlanetScaleにすでにデータベーススキーマがある場合は、既存のプロジェクトでイントロスペクションを使用する
- スキーマの変更をデータベースにプッシュするために
db push
を使用する - PlanetScaleのデータベースサーバーと通信するために、アプリケーションでPrisma Clientを使用する
考慮すべき相違点
PlanetScaleのブランチングモデルとスケーラビリティのための設計は、考慮すべきいくつかの相違点があることを意味します。Prisma ORMでPlanetScaleを使用することを決定する際には、以下の点に留意する必要があります。
-
ブランチングとデプロイリクエスト。PlanetScaleは、スキーマ変更をテストできる開発ブランチと、直接的なスキーマ変更から保護された本番ブランチの2種類のデータベースブランチを提供します。変更はまず開発ブランチで作成され、その後デプロイリクエストを使用して本番環境にデプロイする必要があります。本番ブランチは高可用性を持ち、自動化された日次バックアップを含みます。詳細については、ブランチとデプロイリクエストの使用方法を参照してください。
-
参照アクションと整合性。複数のデータベースサーバーにわたるスケーリングをサポートするため、PlanetScaleはデフォルトで外部キー制約を使用しません。これは通常、リレーショナルデータベースで異なるテーブル間のデータの関係を強制するために使用され、ユーザーはアプリケーションでこれを手動で処理するよう求められます。ただし、PlanetScaleデータベース設定で明示的に有効にすることも可能です。これらを明示的に有効にしない場合でも、
prisma
リレーションモードでPrisma ClientでリレーションをエミュレートするPrisma ORMの機能を使用して、データのこれらの関係を維持し、参照アクションの使用を許可できます。詳細については、Prisma Clientでリレーションをエミュレートする方法を参照してください。 -
外部キーにインデックスを作成する。Prisma ORMでリレーションをエミュレートする場合(つまり、データベースレベルで外部キー制約を使用しない場合)、外部キーに専用のインデックスを作成する必要があります。標準のMySQLデータベースでは、テーブルに外部キー制約を持つ列がある場合、その列に自動的にインデックスが作成されます。PlanetScaleが外部キー制約を使用しないように設定されている場合、Prisma Clientがリレーションをエミュレートしても、これらのインデックスは現在作成されず、クエリが適切に最適化されない問題につながる可能性があります。これを避けるには、Prisma ORMでインデックスを作成できます。詳細については、外部キーにインデックスを作成する方法を参照してください。
-
db push
によるスキーマ変更。開発ブランチを本番ブランチにマージすると、PlanetScaleは自動的に2つのスキーマを比較し、独自のスキーマ差分を生成します。これは、独自のマイグレーションファイルの履歴を生成するPrisma ORMのprisma migrate
ワークフローが、PlanetScaleを使用する場合には自然にフィットしないことを意味します。これらのマイグレーションファイルは、ブランチがマージされたときにPlanetScaleによって実行される実際のスキーマ変更を反映しない可能性があります。警告PlanetScaleでスキーマ変更を行う際には、
prisma migrate
の使用をお勧めしません。代わりに、prisma db push
コマンドを使用することをお勧めします。その動作例については、
db push
でスキーマ変更を行う方法を参照してください。 -
イントロスペクション。既存のデータベースをイントロスペクトし、PlanetScaleデータベースで外部キー制約を有効にしていない場合、通常、テーブルを接続する外部キーに基づいて定義されるリレーションがないスキーマが得られます。その場合、不足しているリレーションを手動で追加する必要があります。詳細については、イントロスペクション後に不足しているリレーションを追加する方法を参照してください。
ブランチとデプロイリクエストの使用方法
Prisma ORMでPlanetScaleに接続する場合、ブランチに応じた正しい接続文字列を使用する必要があります。特定のデータベースブランチの接続URLは、PlanetScaleアカウントのブランチの概要ページに移動し、「Connect」ドロップダウンを選択することで見つけることができます。「Passwords」セクションで新しいパスワードを生成し、ドロップダウンから「Prisma」を選択すると、Prisma形式の接続URLが取得されます。PlanetScaleデータベースへの接続方法の詳細については、Prisma ORMのGetting Startedガイドを参照してください。
すべてのPlanetScaleデータベースは、main
というブランチで作成されます。これは最初は開発ブランチであり、スキーマ変更をテストするために使用できます。そこで行った変更に満足したら、それを本番ブランチに昇格させることができます。新しい変更は開発ブランチにのみプッシュできるため、それ以降の変更は別の開発ブランチで作成し、その後デプロイリクエストを使用して本番環境にデプロイする必要があります。
本番ブランチにプッシュしようとすると、エラーメッセージ Direct execution of DDL (Data Definition Language) SQL statements is disabled on this database.
が表示されます。
PlanetScaleでリレーションを使用する方法(および参照整合性を有効にする方法)
オプション1: Prisma Clientでリレーションをエミュレートする
1. relationMode = "prisma"
を設定する
PlanetScaleは、デフォルトでデータベーススキーマに外部キー制約を使用しません。しかし、Prisma ORMは、Prismaスキーマのモデル間の参照整合性を強制するために、基盤となるデータベースの外部キー制約に依存しています。
Prisma ORMバージョン3.1.1以降では、prisma
リレーションモードでPrisma Clientでリレーションをエミュレートすることができ、これによりデータベースに外部キー制約を必要としなくなります。
Prisma Clientでリレーションのエミュレーションを有効にするには、datasource
ブロックのrelationMode
フィールドを"prisma"
に設定します。
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
relationMode = "prisma"
}
リレーションモードを設定する機能は、Prisma ORMバージョン3.1.1のreferentialIntegrity
プレビュー機能の一部として導入され、Prisma ORMバージョン4.8.0以降で一般利用可能になりました。relationMode
フィールドはPrisma ORMバージョン4.5.0で名前が変更され、以前はreferentialIntegrity
という名前でした。
relationMode
フィールドのデフォルトオプションである"foreignKeys"
を使用してPrismaスキーマでリレーションを使用すると、外部キーを作成しようとしたときにPlanetScaleはエラーを発生させ、Prisma ORMはP3021エラーメッセージを出力します。(バージョン2.27.0より前では、生のデータベースエラーが出力されます。)
2. 外部キーにインデックスを作成する
Prisma Clientでリレーションをエミュレートする場合、独自のインデックスを作成する必要があります。インデックスを追加したい状況の例として、投稿とコメントを含むブログのスキーマを見てみましょう。
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}
Comment
モデルのpostId
フィールドは、Post
モデルの対応するid
フィールドを参照しています。しかし、これはPlanetScaleでは外部キーとして実装されていないため、このカラムには自動インデックスがありません。これは、一部のクエリが十分に最適化されない可能性があることを意味します。例えば、特定の投稿id
を持つすべてのコメントをクエリする場合、PlanetScaleはフルテーブルスキャンを実行する必要があるかもしれません。これは処理が遅くなる可能性があり、またPlanetScaleの課金モデルが読み取られた行数に対して課金するため、コストが高くなる可能性もあります。
これを避けるには、Prisma ORMの@@index
引数を使用してpostId
フィールドにインデックスを定義できます。
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
@@index([postId])
}
その後、この変更をdb push
を使用してスキーマに追加できます。
バージョン4.7.0以降では、Prisma ORMはリレーションスカラフィールドにインデックスがないリレーションがある場合に警告します。詳細については、インデックスの検証を参照してください。
注意すべき点の1つは、暗黙の多対多リレーションにはこの方法でインデックスを追加できないことです。クエリ速度やコストが問題になる場合は、代わりに明示的な多対多リレーションを使用することを検討してください。
オプション2: PlanetScaleデータベース設定で外部キー制約を有効にする
PlanetScaleデータベースでの外部キー制約のサポートは、2024年2月から一般提供されています。PlanetScaleドキュメントの手順に従って、データベースで有効にしてください。
その後、追加の設定なしでPrisma ORMを使用し、Prismaスキーマでリレーションを定義できます。
その場合、外部キー制約をサポートする他のデータベースと同様にリレーションを定義できます。例えば、
model Post {
id Int @id @default(autoincrement())
title String
content String
likes Int @default(0)
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
}
このアプローチでは、以下を行う必要はありません。
- Prismaスキーマで
relationMode = "prisma"
を設定する - 外部キーに追加のインデックスを定義する
また、イントロスペクションはデータベース内の外部キー制約を検出できるため、Prismaスキーマにリレーションフィールドを自動的に作成します。
db push
でスキーマ変更を行う方法
PlanetScaleでdb push
を使用するには、まずPrisma Clientでリレーションのエミュレーションを有効にする必要があります。参照エミュレーションを有効にせずにブランチにプッシュすると、エラーメッセージ Foreign keys cannot be created on this database.
が表示されます。
例として、上記のブログ投稿スキーマに新しいexcerpt
フィールドを追加するとします。まず、新しい開発ブランチを作成し、それに接続する必要があります。
次に、schema.prisma
ファイルに以下を追加します。
model Post {
id Int @id @default(autoincrement())
title String
content String
excerpt String?
likes Int @default(0)
comments Comment[]
}
model Comment {
id Int @id @default(autoincrement())
comment String
postId Int
post Post @relation(fields: [postId], references: [id], onDelete: Cascade)
@@index([postId])
}
これらの変更をプッシュするには、ターミナルでプロジェクトディレクトリに移動し、以下を実行します。
npx prisma db push
開発ブランチでの変更に満足したら、デプロイリクエストを開いて本番ブランチにデプロイできます。
その他の例については、db push
を使用したPrisma ORMによる自動マイグレーションに関するPlanetScaleのチュートリアルを参照してください。
イントロスペクション後に不足しているリレーションを追加する方法
注: このセクションは、Prisma ORMで外部キー制約をエミュレートするために
relationMode = "prisma"
を使用している場合にのみ関連します。PlanetScaleデータベースで外部キー制約を有効にしている場合は、このセクションを無視してかまいません。
npx prisma db pull
でイントロスペクトした後、得られるスキーマには一部のリレーションが欠けている場合があります。例えば、以下のスキーマにはUser
モデルとPost
モデル間のリレーションが欠けています。
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String @db.VarChar(255)
content String?
authorId Int
@@index([authorId])
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
}
この場合、リレーションを手動で追加する必要があります。
model Post {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
title String @db.VarChar(255)
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int
@@index([authorId])
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
}
より詳細な例については、PlanetScaleのGetting Startedガイドを参照してください。
Prismaスキーマでシャードキーを定義する方法 (プレビュー)
データベースの負荷が増加したときにスケールアップするための一般的な手法として、シャーディングがよく知られています。
v6.10.0より、Prisma ORMはPrismaスキーマの@shardKey
および@@shardKey
属性を介して、PlanetScaleでのシャーディングをネイティブに(プレビュー機能として)サポートしています。これらの属性は、データベース設定でシャードキーとして機能するモデルのフィールドに適用できます。
シャードキー属性を使用するには、generator
でshardKeys
プレビュー機能を指定する必要があります。
generator client {
provider = "prisma-client-js"
output = "../generated/prisma"
previewFeatures = ["shardKeys"]
}
これで、@shardKey
と@@shardKey
属性を使用できます。
単一カラムのシャードキー
model User {
id String @default(uuid())
region String @shardKey
}
複数カラムのシャードキー
model User {
id String @default(uuid())
country String
customerId String
@@shardKey([country, customerId])
}
Prisma ORMでPlanetScaleサーバーレスドライバーを使用する方法 (プレビュー)
PlanetScaleサーバーレスドライバーは、HTTP経由でデータベースと通信し、クエリを実行する方法を提供します。
Prisma ORMをPlanetScaleサーバーレスドライバーと組み合わせて、@prisma/adapter-planetscale
ドライバーアダプターを使用して利用できます。このドライバーアダプターにより、HTTP経由でデータベースと通信できます。
この機能は、Prisma ORMバージョン5.4.2以降でプレビュー版として利用可能です。
始めるには、driverAdapters
プレビュー機能フラグを有効にします。
generator client {
provider = "prisma-client-js"
previewFeatures = ["driverAdapters"]
}
Prisma Clientを生成する
npx prisma generate
接続文字列のホスト値をaws.connect.psdb.cloud
に更新してください。これに関する詳細については、こちらで確認できます。
DATABASE_URL='mysql://johndoe:strongpassword@aws.connect.psdb.cloud/clear_nightsky?sslaccept=strict'
PlanetScale用のPrisma ORMアダプター、PlanetScaleサーバーレスドライバー、およびundici
パッケージをインストールします。
npm install @prisma/adapter-planetscale undici
Node.jsバージョン18未満を使用する場合、カスタムのフェッチ関数実装を提供する必要があります。Nodeの組み込みフェッチのベースとなっているundici
パッケージを推奨します。Node.jsバージョン18以降には組み込みのグローバルfetch
関数が含まれているため、追加のパッケージをインストールする必要はありません。
Prisma Clientインスタンスを更新して、PlanetScaleサーバーレスドライバーを使用するようにします。
import { PrismaPlanetScale } from '@prisma/adapter-planetscale'
import { PrismaClient } from '@prisma/client'
import dotenv from 'dotenv'
import { fetch as undiciFetch } from 'undici'
dotenv.config()
const connectionString = `${process.env.DATABASE_URL}`
const adapter = new PrismaPlanetScale({ url: connectionString, fetch: undiciFetch })
const prisma = new PrismaClient({ adapter })
これにより、完全に型安全な状態で通常通りPrisma Clientを使用できます。Prisma Migrate、イントロスペクション、およびPrisma Studioは、Prismaスキーマで定義された接続文字列を使用して以前と同様に動作し続けます。
Prisma ORMとPlanetScaleの使用についてさらに詳しく
Prisma ORMでPlanetScaleを使用する最も速い方法は、Getting Startedドキュメントを参照することです。
これらのチュートリアルでは、PlanetScaleへの接続、スキーマ変更のプッシュ、Prisma Clientの使用について説明します。
Prisma ORMとPlanetScaleを一緒に使用する際のベストプラクティスに関するさらなるヒントは、私たちのビデオをご覧ください。