2024年12月19日

Prisma ORMに関する5つのよくある誤解

Prisma ORMに関する5つのよくある誤解の真相を探りましょう。この記事では、それらの誤解を解き、その起源を探り、事実とフィクションを楽しく区別します。

Top 5 Myths about Prisma ORM

誤解1:Prisma ORMは遅い

2021年にPrisma ORMを本番リリースした当初、私たちは「まず動かす、次に正しくする、そして速くする」というアプローチに従いました。これは、Prisma ORMの初期バージョンが特に速度に最適化されていなかったことを意味します。

しかし、それ以来、私たちはパフォーマンスに多大な投資を行い、ほぼすべてのリリースでパフォーマンスの改善をリリースしてきました。

また、TypeScriptエコシステムで最も人気のある3つのORMを比較するオープンソースのORMベンチマークを作成し、Prisma ORMのパフォーマンスが他と比較して同等か、場合によってはより高速であることを発見しました。

ほぼすべてのリリースにおける主要なパフォーマンス改善

Prisma ORMは、3週間サイクルで着実かつ信頼性の高いリリースサイクルを維持しています。prisma/prismaリポジトリのリリースページを確認すると、ほぼすべてのリリースに何らかのパフォーマンス改善が含まれていることに気づくでしょう。特定のSQLクエリの最適化(例:5.11.05.9.05.7.05.4.05.2.05.1.0、…)、createManyAndReturnのような新しいバッチクエリの導入(5.14.0)、コールドスタートの9倍高速化5.0.0)、あるいはネイティブJSベースドライバのサポートの導入(5.4.0)などです。

また、言語間のシリアライズのオーバーヘッドを削減するため、RustベースのQuery EngineをRustからTypeScriptに書き換える作業も進めており、この変更からも顕著なパフォーマンス改善が期待されます。

Prisma ORMで最適なJOIN戦略を選択

Prisma ORMを利用する開発者にとってのもう一つの大きな利点は、関連クエリに対して最適なJOIN戦略を選択できるようになったことです。

原則として、外部キーを介して関連付けられた複数のテーブルからデータをクエリする必要がある場合、2つの異なるアプローチがあります。

データベースレベル: 単一クエリで`JOIN`キーワードを使用する

このアプローチでは、SQLのJOINキーワードを使用して単一のクエリをデータベースに送信し、データはデータベースによって直接結合されます。

Blog image

アプリケーションレベル: 複数のクエリを送信し、アプリケーションで結合する

アプリケーションレベルで結合する場合、個々のテーブルに対する複数のクエリをデータベースに送信し、アプリケーションでデータを結合します。

Blog image

どちらをいつ使うべきか?

ユースケース、データセット、スキーマ、およびその他のいくつかの要因に応じて、一方の戦略がもう一方よりもパフォーマンスが高い場合があります。アプリケーションレベルの結合方法は、結合分解(join decomposition)とも呼ばれ、高性能な環境でよく使用されます。

多くの高性能ウェブサイトでは結合分解を使用しています。マルチテーブル結合ではなく、複数のシングルテーブルクエリを実行し、その後アプリケーションで結合を実行することで、結合を分解できます。

高性能MySQL 第2版 | O'Reilly

Prisma ORM 5.7.0までは、Prisma ORMは常にアプリケーションレベルのJOIN戦略を使用していました。しかし、5.7.0のリリースにより、ユースケースに最適なJOIN戦略を選択できるようになり、常にクエリで最高のパフォーマンスを得られるようになりました。

ORMベンチマーク: 主要なパフォーマンス差なし

これらの改善を経て、Prisma ORMが他のORMライブラリと比較してどの程度のパフォーマンスにあるのかを知りたくなりました。そこで、TypeORM、Drizzle ORM、Prisma ORMのクエリパフォーマンスを比較する透明なベンチマークを作成しました。

ベンチマークのリポジトリはオープンソースであり、誰でも結果を再現し、私たちと共有することを歓迎します。

Blog image

では、ベンチマークは何を示したのでしょうか?

TLDR: 私たちが収集したデータに基づいて、あるORMが常に他のORMよりも優れたパフォーマンスを発揮すると結論付けることはできません。むしろ、それはそれぞれのクエリ、データセット、スキーマ、そしてクエリが実行されるインフラストラクチャに依存します。

ベンチマークの設定、方法論、および結果の詳細については、こちらをご覧ください: パフォーマンスベンチマーク: TypeScript ORMおよびデータベース間のクエリレイテンシ比較

Prisma Optimizeでクエリを高速化

ベンチマークを実行して得られた重要な洞察の1つは、どのようなツールを使用しても、高速なクエリも低速なクエリも書くことができるということでした。つまり、最終的にデータベースクエリを高速に保つ責任の多くは、開発者自身にあるということです。

Blog image

Prisma ORMを使用する開発者がクエリを可能な限り高速に実行できるようにするため、私たちは最近Prisma Optimizeをリリースしました。これは、Prisma ORMを使用してデータベースに送信するクエリを分析し、改善方法に関する洞察と推奨事項を提供するツールです。

誤解2:低レベルDB機能が使えない

Prisma ORMは、ORMとしての性質上、生産性、信頼性、およびデータベース作業時の全体的な開発者体験を向上させるために、SQLに対する高レベルの抽象化を提供します。

この高レベルの抽象化は、データベースの構造を記述する「人間が読める」Prismaスキーマと、データベースのクエリを実行するための「直感的」なPrisma Client APIに表れています。

しかし、抽象化によって基礎となる技術(Prisma ORMの場合:データベース)の機能にアクセスできなくなることもあるため、より低い抽象化レベルに降りるための適切なエスケープハッチが必要です。

そのため、より高度なシナリオやエッジケースで必要となる重要な機能を犠牲にしないために、Prisma ORMは開発者がデータベースの基盤機能にアクセスするための便利なフォールバックを提供しています。

カスタマイズされたマイグレーションにより、開発者はあらゆるSQL機能を使用可能

データベースが持つすべての機能をPrismaスキーマで表現することはできませんが、Prisma Migrateによって生成されるマイグレーションファイルをカスタマイズすることで、これらを利用することができます。

そのためには、新しいマイグレーションを作成する際に--create-onlyフラグを使用し、データベースに適用する前に編集を加えるだけで済みます。

カスタマイズされたマイグレーションを使用することで、データベーススキーマを自由に操作しながら、すべての変更がPrisma Migrateによって実行され、そのマイグレーション履歴で追跡されることを保証できます。

Prisma ORMでタイプセーフなSQLを書く

クエリに関して言えば、開発者が高レベルのクエリAPIでは表現できない生のSQLに落とし込んでクエリを記述する方法は主に2つあります。

TypedSQL:生SQLをタイプセーフに

Prisma ORMは、今や両方の長所を提供します。ほとんどのクエリに対応する便利な高レベル抽象化と、生SQLに対応する柔軟でタイプセーフなエスケープハッチです。

アプリケーションで記述する必要がある生のSQLクエリの例を考えてみましょう

生成ステップの後、Prisma Clientの新しい$queryRawTypedメソッドを通じてconversionByVariantクエリを使用できるようになります。

これについての詳細はブログでご確認ください: TypedSQL発表: Prisma ORMで生SQLクエリをタイプセーフに

Kysely SQLクエリ構築拡張機能を使用する

もう一つの選択肢は、Kysely用のPrisma Client拡張機能を使用することです。これにより、開発者はTypeScript APIを使用してSQLクエリを構築できます。例えば、Kysely拡張機能を使用すると、PrismaでSQLクエリを次のように記述できます。

これにより、TypeScriptとPrisma ORMから離れることなく、高度なSQLクエリを記述することができます。

豆知識:KyselyのコアメンテナーであるIgalが最近Prismaのチームに加わりました 😄

誤解3:Prisma ORMは内部でGraphQLを使用している

Prismaコミュニティにどれくらい長くいるかにもよりますが、これは驚きかもしれません。PrismaはかつてGraphcoolというGraphQLのBackend-as-a-Serviceプロバイダーでした。

Blog image

2018年、GraphcoolはPrismaにブランド変更し、APIレイヤーからデータベースへと「抽象化のはしご」を降りてきました。

Prismaの最初のバージョン(ORMになる前)は、APIサーバーとデータベースの間に位置するCRUD GraphQLレイヤーでした。

この時点でのPrisma 1の主な価値は、便利なデータモデリング、マイグレーション、クエリ機能であり、これらはすべてGraphQLを介して行われていました。

Prismaの利用を簡素化し、ユーザーが完全に独立したサーバーをセットアップ・維持する必要をなくすため、PrismaのGraphQLエンジンをRustで書き直し、npm installでダウンロード可能なバイナリとして提供しました。

クエリエンジンは、アプリケーションサーバー上でサイドカープロセスとしてGraphQLサーバーを実行していました。開発者はPrisma Clientを使用してそれとやり取りし、TypeScriptでクエリを記述していました。これがPrisma ORMの初期アーキテクチャでした。

それ以来、私たちはアーキテクチャに数え切れないほどの最適化を施してきました。特に注目すべきは、RustとTypeScript間の通信にN-APIを導入し、GraphQLをカスタムのJSONベースのワイヤプロトコルに置き換え、JSネイティブデータベースドライバの使用を可能にするなど、他にも多くの改善を行いました!

現在、Prisma ORMにはGraphQLの痕跡は一切残っていません。そして、私たちはここで立ち止まることなく、Prisma ORMのアーキテクチャ改善を続けています。次のステップは、SQL生成という重い処理を行うQuery EngineをRustからTypeScriptに移行し、Prisma ORMをさらに効率的にすることです。

誤解4:Prisma Clientはnode_modules内に置かなければならない

開発者がPrisma ORMについて抱く一般的な誤解の一つは、生成されたPrisma Clientライブラリがnode_modules内に存在しなければならないというものです。

しかし、node_modulesは、慣れ親しんだ開発者体験を提供し、簡単なインポートを可能にするためのデフォルトの場所でしかありません。

この場所は、generatorブロックにカスタムのoutputパスを提供することで、簡単にカスタマイズできます。

その場合、importステートメントを調整し、ファイルシステムからPrisma Clientをインポートする必要があります。上記の例を考慮すると、importは次のようになります。

これは、モノレポや、Prisma Clientをnode_modulesに生成すると問題が発生する可能性のある特殊な環境で作業している場合に非常に役立ちます。

誤解5:Prismaはサーバーレス/Edge環境でうまく動作しない

Prisma ORMが設計された当時、サーバーレスおよびEdgeデプロイメントはまだ初期段階の新興技術でした。それ以来、それらは多くの開発チームが依存する一般的なデプロイメントモデルとなっています。

Query Engineバイナリと内部GraphQLサーバーを伴うPrisma ORMの初期アーキテクチャは、サーバーレス環境向けに最適化されておらず、多くの問題がありました。

  • GraphQLベースのワイヤプロトコルによるコールドスタートの遅延。
  • (NeonやPlanetScaleのような)モダンなDBプロバイダーのサーバーレスドライバを使用する機能がないこと。これにより、EdgeでのPrisma Clientの使用が完全に妨げられていました。
  • Query Engineバイナリによるバンドルサイズの肥大化。
  • ローカルマシンがターゲットマシンと異なる場合にbinaryTargetsを宣言する必要があることによる複雑さの増加。

私たちはこれらの問題をすべて認識し、時間をかけて解決策を実装し、サーバーレス環境におけるPrisma ORMのDXを劇的に改善しました。

  • Query Engineの内部からGraphQLを削除し、コールドスタートを9倍高速化したため、コールドスタートはもはや問題ではありません。
  • ドライバーアダプターのおかげで、サーバーレスおよびその他のJSネイティブデータベースドライバーpgなど)がPrisma ORMで利用できるようになりました。
  • Prisma ORMのバンドルサイズは1MB未満に削減され、主要なEdgeファンクションプロバイダー(無料プランの制限が3MBであるCloudflareなど)の無料プランでも使用できるようになりました。
  • …そして、さらなる改善に取り組んでいます。RustからTypeScriptへの移行により、binaryTargetsを宣言する必要がなくなり、全体的にPrisma ORMのデプロイメントがこれまで以上にスムーズになるでしょう。

Prisma ORMを最高のDBライブラリにするお手伝いを!💚

Prismaでは、コミュニティから寄せられるフィードバックを非常に重視しています!Prisma ORMに関する誤解の中には過去には真実であったものもありますが、私たちはユーザーの声に耳を傾け、状況を改善するために懸命に努力してきました。

オープンソースガバナンスに対する私たちのアプローチについてさらに詳しく知りたい場合は、Prisma ORMマニフェストをご覧ください。

私たちは、Prisma ORMをTypeScriptエコシステムで最高のDX(開発者体験)を持つ最も高性能なデータベースライブラリにするための努力を続けます。他にどのような改善をご覧になりたいか、GitHubDiscord、またはXでお知らせください🙌

Prisma ORMに興味を持っていただけたなら、開発者コミュニティでこれらの誤解が浮かび上がったときにこの投稿を共有することで、その誤解を解消する手助けをすることができます。また、他に解明してほしい誤解があれば、ぜひ教えてください

次回の投稿をお見逃しなく!

Prismaニュースレターに登録する

© . All rights reserved.