Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Prisma2 with Graphql

joe_re
August 28, 2020
830

Prisma2 with Graphql

GraphqlTokyo #10 LT 資料

joe_re

August 28, 2020
Tweet

Transcript

  1. PRISMA2 WITH GRAPHQL
    @joe_re

    View Slide

  2. INTRODUCTION
    WHO AM I?
    ▸ twitter: @joe_re
    ▸ github: @joe-re
    ▸ GraphQL Tokyoのオーガナイザの1⼈です
    ▸ オンラインレッスン/ミーティングのサービスを作っています(@classdo)
    ▸ Prisma1は結構⻑く使ってきました (Graphcool時代から数えると2年半ぐらい)

    View Slide

  3. PRISMA1 AND PRISMA2
    DIFFERENCE OF PRISMA1 AND PRISMA2
    ▸ Prisma1はGraphQLのバックエンドサーバ(Prisma Server)を提供し、
    http経由でDBのマイグレーションの指示や、GraphQLクエリとDBクエリの変
    換、データの更新や取得を⾏う
    ▸ Prisma2ではPrisma Serverは撤廃され、アプリケーションコードから直接Prisma
    Engine(Rust製)というバイナリのAPIを叩いてデータの取得やマイグレーション
    を⾏う
    ▸ クライアントのAPIインターフェイスなどは受け継いでいるものの、
    アーキテクチャからして全くの別物

    View Slide

  4. * Prisma2のプレビューのアナウンスメントブログより抜粋
    https://www.prisma.io/blog/announcing-prisma-2-zq1s745db8i5
    PRISMA1 AND PRISMA2

    View Slide

  5. WHAT IS PRISMA2
    OVERVIEW OF PRISMA2
    ▸ Prisma2ではAPIサーバ側に直接DB接続を持つ
    ▸ イメージ的にはよりORMに近い動きになる
    (ただしPrismaは独⾃DSLに基づいたクライアントのオートジェネレーションや
    マイグレーションを提供することから⾃身のことをORMではなく
    database toolkitと位置づけしている)

    View Slide

  6. WHAT IS PRISMA2
    OVERVIEW OF PRISMA2
    アプリケーションサイド
    Prisma Client (旧Photon)
    クライアントのオートジェネレーションツール
    Prisma Migrate (旧Lift)
    独⾃DSL(.prisma)に基づいたマイグレーション
    ツール
    Prisma CLI
    それぞれのツールの呼び出しのコマンドの提供
    Prisma Studio
    データベースのビジュアルエディタ
    クエリエンジン
    Prisma Engine
    データベースへのクエリエンジン(Rust製)
    バイナリとして提供されて、アプリケーション
    サーバに配置される
    *Prismaの公式ドキュメント、Query Engineのページより抜粋
    https://www.prisma.io/docs/reference/tools-and-interfaces/prisma-client/query-engine

    View Slide

  7. WHAT IS PRISMA2
    Q:あれ、GraphQL関係なくね?
    ▸ はい、ありません

    View Slide

  8. WHAT IS PRISMA2
    ▸ Prisma2はPrisma1からクエリエンジンとクライアント(ORM)やマイグレーション
    やその周辺ツール部分をブラッシュアップしたプロダクト
    ▸ 基本的にGraphQLとのつながりはない (RestAPIサーバでもCLIツールでもなんで
    も使える)
    ▸ GraphQLの実装はNexusを使うことが推奨されている

    View Slide

  9. WHAT IS NEXUS
    WHAT IS NEXUS
    ▸ GraphQLのアプリケーションサーバを開発するTypeScriptのフレームワーク
    ▸ レポジトリはPrismaのオーガナイゼーション配下にはないけど、
    ドキュメントに何度も登場したりPrismaの開発者がコントリビュートしていたり
    ほぼ公式の位置づけ
    ▸ Schema-First開発をシンプルにして、その利便性とCode-First開発の保守性、
    開発の素早さとを両⽴させることを⽬指している

    View Slide

  10. WHAT IS NEXUS
    DEVELOPMENT GRAPHQL SERVER ON NEXUS
    ▸ Code-Firstのアプローチで、先にResolverを記述する
    (graphql-jsの上で開発していて、⾒た⽬はSDLっぽくなる)
    ▸ Resolverの記述に伴い、開発サーバがリアルタイムにコードをビルドして、
    GraphQLスキーマファイルとそれに対応した型ファイルの⽣成を⾏う
    ▸ 全てをリアルタイムにビルドする & 完全な型付けを提供することで、
    ⼀般的なSchema-Firstにおける、GraphQLスキーマの記述 -> コードジェネレー
    ションの⼿間を省きつつその利点を得る

    View Slide

  11. WHAT IS NEXUS
    DEVELOPMENT GRAPHQL SERVER ON NEXUS
    api/Post.ts (Resolver)
    app.graphql
    node_modules/@type/typegen-nexus/index.d.ts
    1. 先にResolverを記述
    2. 開発サーバが変更を検知
    3-1. GraphQLスキーマファイルの⽣成
    3-2. Resolverの型ファイルを⽣成
    (node_modules/@types以下に⽣成される)

    View Slide

  12. DEMO

    View Slide

  13. WHAT IS NEXUS
    THE IMPRESSION OF NEXUS
    ▸ ⼩さい範囲で試している範囲では快適な体験
    ▸ 個⼈的にはSchema-First寄りの意⾒を持っていたけど、
    このアプローチが上⼿くスケールするならあり
    (ただし今までPrismaは途中で開発をやめたプロダクトが少なからず
    あるので少し⼼配)
    ▸ プロダクトが⼤きくなった時のコードジェネレーションの速度が気になる

    View Slide

  14. 時間があればちょっとだけ
    クエリオプティマイズの話をします

    View Slide

  15. GraphQLでN+1起きがち問題ありますよね??

    View Slide

  16. こんなの
    ユーザ全件を取得するクエリ定義 ユーザのタイプ定義 (Type Resolver)
    ユーザ1件に対して1件のProfileを取得する

    View Slide

  17. PRISMA1ではどう解決されていたか
    ▸ Prisma1ではPrisma Serverへ⾶ぶリクエストがまとめられて、⼀気にサーバ側で
    解決される
    https://github.com/prisma-labs/http-link-dataloader
    ▸ ⼀⾒N+1が起きそうなコードを書いても、
    ある程度のところまでは⾃動でオプティマイズされる
    ( 深刻なパフォーマンスの問題が出ればもちろん真剣に取り組む必要はある)
    ▸ Prisma1からPrisma2へ移⾏を考える上で検証は避けては通れないところ

    View Slide

  18. 試してみた

    View Slide

  19. 結果
    ▸ 1 つ⽬: ユーザ全体を取得する(params: [-1, 0])
    SELECT `dev`.`User`.`id`, `dev`.`User`.`email`, `dev`.`User`.`name` FROM `dev`.`User` WHERE 1=1 LIMIT ? OFFSET ?
    ▸ 2つ⽬-4つ⽬: ユーザ単位でポストの全体を取得する (params: [userId, -1, 0])
    SELECT `dev`.`Post`.`id`, `dev`.`Post`.`authorId`, `dev`.`Post`.`content`, `dev`.`Post`.`published`, `dev`.`Post`.`title`
    FROM `dev`.`Post` WHERE (`dev`.`Post`.`id`) IN (SELECT `t0`.`id` FROM `dev`.`Post` AS `t0` INNER JOIN `dev`.`User`
    AS `j0` ON (`j0`.`id`) = (`t0`.`authorId`) WHERE `j0`.`id` = ?) LIMIT ? OFFSET ?
    ▸ 5つ⽬: Profile取得対象のユーザの存在を確かめる(?) (params: [1, 2, 3, -1, 0])
    SELECT `dev`.`User`.`id` FROM `dev`.`User` WHERE `dev`.`User`.`id` IN (?,?,?) LIMIT ? OFFSET ?
    ▸ 6つ⽬: Profileの取得(params: [1, 2, 3, -1, 0])
    SELECT `dev`.`Profile`.`id`, `dev`.`Profile`.`bio`, `dev`.`Profile`.`userId` FROM `dev`.`Profile` WHERE
    `dev`.`Profile`.`userId` IN (?,?,?) LIMIT ? OFFSET ?
    まとめられてる!

    View Slide

  20. 気になったのでコードを追ってみたところ、現状はfindOneのクエリはまとめられるようです
    ▸ Client側のリクエストのバッチ送信処理
    https://github.com/prisma/prisma/blob/2.5.1/src/packages/client/src/runtime/Dataloader.ts#L31
    ▸ クエリエンジン側のオプティマイゼーションの判定処理 (同じファイルにオプティマイゼーションの処理も
    ある)
    https://github.com/prisma/prisma-engines/blob/2.6.0-dev.44/query-engine/core/src/query_document/
    mod.rs#L61
    ▸ GraphQLのResolverで最もN+1が起きやすいコードはこれだと思うので、ここがオプティマイズされるのは
    嬉しい
    ▸ オプティマイズ効かせるのに少しコツがいりそうなので、このあたりもドキュメントになって欲しい気持ち

    View Slide

  21. THANK YOU!

    View Slide