メインコンテンツにスキップ

PlanetScale

PrismaとPlanetScaleは、PrismaのORMとPlanetScaleのスケーラブルなMySQLベースのプラットフォームを活用し、データアクセスアプリケーションの高速かつ型安全な開発を最適化する開発環境を提供します。

このドキュメントでは、Prisma ORMとPlanetScaleを使用する際の概念について説明し、PlanetScaleと他のデータベースプロバイダーとの共通点および相違点を解説し、PlanetScaleと統合するためのアプリケーション設定プロセスを案内します。

PlanetScaleとは?

PlanetScaleは、Vitessデータベースクラスタリングシステムを使用して、MySQL互換のデータベースプラットフォームを提供します。主な機能は以下の通りです。

  • エンタープライズレベルのスケーラビリティ。PlanetScaleは、複数のデータベースサーバーにわたるスケーリングをサポートする、高可用性プロダクションデータベースクラスターを提供します。これは、接続制限の管理という問題を回避できるため、サーバーレス環境で特に役立ちます。
  • データベースブランチ。PlanetScaleでは、データベーススキーマのブランチを作成できるため、開発ブランチで変更をテストしてから本番データベースに適用できます。
  • ノンブロッキングスキーマ変更のサポート。PlanetScaleは、データベースをロックしたり、ダウンタイムを引き起こしたりすることなく、ユーザーがデータベーススキーマを更新できるワークフローを提供します。

他のデータベースプロバイダーとの共通点

Prisma ORMをPlanetScaleと組み合わせて使用する際の多くの側面は、他のリレーショナルデータベースでPrisma ORMを使用する場合とまったく同じです。引き続き以下のことができます。

考慮すべき相違点

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"に設定します。

schema.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でリレーションをエミュレートする場合、独自のインデックスを作成する必要があります。インデックスを追加したい状況の例として、投稿とコメントを含むブログのスキーマを見てみましょう。

schema.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)
}

CommentモデルのpostIdフィールドは、Postモデルの対応するidフィールドを参照しています。しかし、これはPlanetScaleでは外部キーとして実装されていないため、このカラムには自動インデックスがありません。これは、一部のクエリが十分に最適化されない可能性があることを意味します。例えば、特定の投稿idを持つすべてのコメントをクエリする場合、PlanetScaleはフルテーブルスキャンを実行する必要があるかもしれません。これは処理が遅くなる可能性があり、またPlanetScaleの課金モデルが読み取られた行数に対して課金するため、コストが高くなる可能性もあります。

これを避けるには、Prisma ORMの@@index引数を使用してpostIdフィールドにインデックスを定義できます。

schema.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)

@@index([postId])
}

その後、この変更をdb pushを使用してスキーマに追加できます。

バージョン4.7.0以降では、Prisma ORMはリレーションスカラフィールドにインデックスがないリレーションがある場合に警告します。詳細については、インデックスの検証を参照してください。

警告

注意すべき点の1つは、暗黙の多対多リレーションにはこの方法でインデックスを追加できないことです。クエリ速度やコストが問題になる場合は、代わりに明示的な多対多リレーションを使用することを検討してください。

オプション2: PlanetScaleデータベース設定で外部キー制約を有効にする

PlanetScaleデータベースでの外部キー制約のサポートは、2024年2月から一般提供されています。PlanetScaleドキュメントの手順に従って、データベースで有効にしてください。

その後、追加の設定なしでPrisma ORMを使用し、Prismaスキーマでリレーションを定義できます。

その場合、外部キー制約をサポートする他のデータベースと同様にリレーションを定義できます。例えば、

schema.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ファイルに以下を追加します。

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モデル間のリレーションが欠けています。

schema.prisma
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?
}

この場合、リレーションを手動で追加する必要があります。

schema.prisma
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でのシャーディングをネイティブに(プレビュー機能として)サポートしています。これらの属性は、データベース設定でシャードキーとして機能するモデルのフィールドに適用できます。

シャードキー属性を使用するには、generatorshardKeysプレビュー機能を指定する必要があります。

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を一緒に使用する際のベストプラクティスに関するさらなるヒントは、私たちのビデオをご覧ください。

© . All rights reserved.