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

GraphQL データ取得高速化

ham
July 06, 2023
220

GraphQL データ取得高速化

tsukiji.graphql #1での発表資料です。
https://tsukiji-graphql.connpass.com/event/281413/

ham

July 06, 2023
Tweet

Transcript

  1. GraphQL
    データ取得高速化
    tsukiji.graphql #1
    2023/07/06
    ham

    View full-size slide

  2. 自己紹介
    【略歴】
    新卒でSIerとして就職
    その後、Web系企業やスタートアップを経てファインディに参画
    ファインディではFindy Team+のフロント&バックエンド開発を担当
    React+Rails+GraphQL+AWSを使って開発しています
    浜田 直人 (ham)
    ファインディ株式会社
    @hamchance0215

    View full-size slide

  3. users {
    id
    profile {
    name
    }
    }
    N+1問題
    – userを複数返却するQuery
    – id fieldはusersテーブルから取得
    – profileはprofilesテーブルから取得
    # Ruby code
    def resolve
    User.all
    end

    View full-size slide

  4. users {
    id
    profile {
    name
    }
    }
    N+1問題
    – usersは10件Hit
    select * from users;
    – profilesを1件ずつ取得 => N+1問題
    select * from profiles where user_id = 1;
    select * from profiles where user_id = 2;

    select * from profiles where user_id = 10;

    View full-size slide

  5. users {
    id
    profile {
    name
    }
    }
    N+1問題
    – usersに対応するprofileを事前ロード
    # Ruby code
    def resolve
    User.all.preload(:profile)
    end

    View full-size slide

  6. users {
    id
    profile {
    name
    }
    }
    N+1問題
    – usersは10件Hit
    select * from users;
    – hitしたusersに対応したprofilesを事前ロード
    select * from profiles
    where user_id in (1, 2, …, 10);

    View full-size slide

  7. users {
    id
    }
    N+1問題
    – usersは10件Hit
    select * from users;
    – fieldに指定していなくてもprofilesを事前ロー
    ドしてしまう
    select * from profiles
    where user_id in (1, 2, …, 10);

    View full-size slide

  8. users {
    id
    profile {
    name
    }
    }
    N+1問題
    – usersに対応するprofileを遅延ロード
    # Ruby code
    def resolve
    # fieldにprofileがある場合、profile
    を取得するuser_idを記憶しておき、最後にま
    とめて取得する
    User.all
    end

    View full-size slide

  9. N+1問題
    – 事前ロード🙅
    – 指定していないfieldも読み込んでしまう
    – 遅延ロード🙆
    – 指定されたfieldのみまとめて取得

    View full-size slide

  10. 無駄な計算

    View full-size slide

  11. user(id:$id) {
    id
    reviewCount
    }
    無駄な計算
    – userを1件返却するQuery
    – userが投稿したレビュー数を取得
    – reviewsテーブルをcount
    # Ruby code
    def resolve(id:)
    user = User.find_by(id:)
    {
    id: user.id,
    review_count: user.reviews.count,
    }
    end

    View full-size slide

  12. user(id:$id) {
    id
    reviewCount
    }
    無駄な計算
    – users
    select * from users where id = 1;
    – reviews
    select count(*) from reviews
    where user_id = 1;

    View full-size slide

  13. user(id:$id) {
    id
    }
    無駄な計算
    – reviewCountを指定していなくても
    reviews.countが計算される
    # Ruby code
    def resolve(id:)
    user = User.find_by(id:)
    {
    id: user.id,
    review_count: user.reviews.count,
    }
    end

    View full-size slide

  14. user(id:$id) {
    id
    }
    無駄な計算
    – reviewCountを指定していなくても
    reviews.countが計算される
    # Ruby code
    def resolve(id:)
    user = User.find_by(id:)
    {
    id: user.id,
    review_count: user.reviews.count,
    }
    end
    reviewCountが指定されているときだけ、
    reviews.countが計算されるような実装に変
    更する!

    View full-size slide

  15. 無駄な計算
    – 常に全てのfieldを計算してしまう🙅
    – 指定されたfieldのみ計算🙆

    View full-size slide

  16. 直列で取得

    View full-size slide

  17. hoge {
    heavy1
    heavy2
    }
    直列で取得
    – heavy1やheavy2は重い処理
    – レスポンスまでheavy1+heavy2の処理時間
    # Ruby code
    def resolve
    {
    heavy1: Hoge.heavy1_process,
    heavy2: Hoge.heavy2_process,
    }
    end

    View full-size slide

  18. hoge {
    heavy1
    heavy2
    }
    直列で取得
    – heavy1とheavy2は同時に行われるので遅い
    方の時間がレスポンスタイムとなる
    # Ruby code
    def resolve
    # heavy1, 2を非同期で取得
    heavy1 = Hoge.sync_heavy1_process
    heavy2 = Hoge.sync_heavy2_process
    {
    heavy1:,
    heavy2:,
    }
    end

    View full-size slide

  19. 直列で取得
    – 直列だと重い場合は並列取得を検討🙆
    – 直列でも十分速い場合は問題なし!
    – 並列取得にすると実装の複雑度が上がるのでメ
    リットがない場合はやらない方が良い

    View full-size slide

  20. - N+1問題
    - 遅延ロードを検討する
    - 無駄な計算
    - fieldが指定されているときだけ計算する
    - 重いfield
    - 並列実行を検討する
    まとめ

    View full-size slide