PlanetScale
Prisma とPlanetScaleは、Prisma の ORM と PlanetScale の高度にスケーラブルな MySQL ベースのプラットフォームを使用して、データアクセスアプリケーションの迅速かつタイプセーフな開発を最適化する開発環境を共同で提供します。
このドキュメントでは、Prisma ORM と PlanetScale の使用に関する概念について説明し、PlanetScale と他のデータベースプロバイダーとの共通点と相違点について解説し、PlanetScale と統合するようにアプリケーションを構成するプロセスをご案内します。
PlanetScale とは?
PlanetScale は、MySQL 互換のデータベースプラットフォームを提供するために、Vitessデータベースクラスタリングシステムを使用しています。機能は次のとおりです。
- エンタープライズスケーラビリティ。 PlanetScale は、複数のデータベースサーバーにわたるスケーリングをサポートする、可用性の高い本番データベースクラスターを提供します。これは、接続制限を管理する必要性を回避するため、サーバーレスコンテキストで特に役立ちます。
- データベースブランチ。 PlanetScale を使用すると、データベーススキーマのブランチを作成できるため、本番データベースに適用する前に、開発ブランチで変更をテストできます。
- ノンブロッキングスキーマ変更のサポート。 PlanetScale は、データベースをロックしたり、ダウンタイムを引き起こしたりすることなく、ユーザーがデータベーススキーマを更新できるワークフローを提供します。
他のデータベースプロバイダーとの共通点
PlanetScale で Prisma ORM を使用する多くの側面は、他のリレーショナルデータベースで Prisma ORM を使用するのと同様です。引き続き以下が可能です。
- Prisma スキーマ言語でデータベースをモデル化する
- スキーマで Prisma ORM の既存の
mysql
データベースコネクタと、PlanetScale が提供する接続文字列を使用する - PlanetScale に既存のデータベーススキーマがある場合は、既存のプロジェクトにイントロスペクションを使用する
db push
を使用して、スキーマの変更をデータベースにプッシュする- アプリケーションでPrisma Clientを使用して、PlanetScale のデータベースサーバーと通信する
考慮すべき相違点
PlanetScale のブランチングモデルとスケーラビリティのための設計は、考慮すべき相違点も多数あることを意味します。Prisma ORM で PlanetScale を使用することを決定する際には、次の点に注意する必要があります。
-
ブランチングとデプロイリクエスト。 PlanetScale は、データベースブランチの 2 つのタイプを提供します。スキーマの変更をテストできる開発ブランチと、直接スキーマ変更から保護されている本番ブランチです。代わりに、変更は最初に開発ブランチで作成し、デプロイリクエストを使用して本番環境にデプロイする必要があります。本番ブランチは可用性が高く、自動日次バックアップが含まれています。詳細については、ブランチとデプロイリクエストの使用方法を参照してください。
-
参照アクションと整合性。 複数のデータベースサーバーにわたるスケーリングをサポートするために、PlanetScale は、デフォルトでは外部キー制約を使用しません。これは通常、リレーショナルデータベースで異なるテーブルのデータ間の関係を強制するために使用され、ユーザーにアプリケーションで手動で処理するように求めます。ただし、PlanetScale データベース設定で明示的に有効にすることができます。これらを明示的に有効にしない場合でも、データ内のこれらの関係を維持し、参照アクションの使用を許可できます。そのためには、Prisma ORM の
prisma
リレーションモードを使用して Prisma Client で関係をエミュレートする機能を使用します。詳細については、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 アカウントからブランチの概要ページに移動し、「接続」ドロップダウンを選択することで見つけることができます。「パスワード」セクションで、新しいパスワードを生成し、ドロップダウンから「Prisma」を選択して、接続 URL の Prisma 形式を取得します。PlanetScale データベースへの接続方法の詳細については、Prisma ORM の入門ガイドを参照してください。
すべての 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 の入門ガイドを参照してください。
Prisma ORM で PlanetScale サーバーレスドライバーを使用する方法 (プレビュー)
PlanetScale サーバーレスドライバーは、HTTP 経由でデータベースと通信し、クエリを実行する方法を提供します。
@prisma/adapter-planetscale
ドライバーアダプターを使用すると、PlanetScale サーバーレスドライバーと共に Prisma ORM を使用できます。ドライバーアダプターを使用すると、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 @planetscale/database undici
Node.js バージョン 18 未満を使用している場合は、カスタムフェッチ関数実装を提供する必要があります。Node の組み込みフェッチのベースとなっている undici
パッケージをお勧めします。Node.js バージョン 18 以降には組み込みのグローバル fetch
関数が含まれているため、追加のパッケージをインストールする必要はありません。
PlanetScale サーバーレスドライバーを使用するように Prisma Client インスタンスを更新します。
import { Client } from '@planetscale/database'
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 client = new Client({ url: connectionString, fetch: undiciFetch })
const adapter = new PrismaPlanetScale(client)
const prisma = new PrismaClient({ adapter })
その後、通常どおりに完全なタイプセーフで Prisma Client を使用できます。Prisma Migrate、イントロスペクション、Prisma Studio は、Prisma スキーマで定義された接続文字列を使用して、これまでどおりに動作し続けます。
Prisma ORM での PlanetScale の使用に関する詳細
Prisma ORM で PlanetScale の使用を開始する最も速い方法は、入門ドキュメントを参照することです。
これらのチュートリアルでは、PlanetScale への接続、スキーマ変更のプッシュ、および Prisma Client の使用のプロセスについて説明します。
Prisma ORM と PlanetScale を一緒に使用する際のベストプラクティスの詳細については、ビデオをご覧ください。