window.pipedriveLeadboosterConfig={です。 ベース:'leadbooster-chat.pipedrive.com'、 companyId:11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2、 } ;(function () { var w = window もし (w.LeadBooster) {なら console.warn('LeadBooster already exists') } else { w.LeadBooster = { {. q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: 関数 (n) { { this.q.push({ t: 'o', n: n, h: h }) this.q.push({ t: 't', n: n }) }, } } })() GraphQL Ruby。パフォーマンスは?- The Codest
The Codest
  • 会社概要
  • サービス
    • ソフトウェア開発
      • フロントエンド開発
      • バックエンド開発
    • Staff Augmentation
      • フロントエンド開発者
      • バックエンド開発者
      • データエンジニア
      • クラウドエンジニア
      • QAエンジニア
      • その他
    • アドバイザリー
      • 監査&コンサルティング
  • 産業
    • フィンテック&バンキング
    • E-commerce
    • アドテック
    • ヘルステック
    • 製造業
    • 物流
    • 自動車
    • アイオーティー
  • 価値
    • CEO
    • CTO
    • デリバリー・マネージャー
  • チーム
  • Case Studies
  • ノウハウ
    • ブログ
    • ミートアップ
    • ウェビナー
    • リソース
採用情報 連絡先
  • 会社概要
  • サービス
    • ソフトウェア開発
      • フロントエンド開発
      • バックエンド開発
    • Staff Augmentation
      • フロントエンド開発者
      • バックエンド開発者
      • データエンジニア
      • クラウドエンジニア
      • QAエンジニア
      • その他
    • アドバイザリー
      • 監査&コンサルティング
  • 価値
    • CEO
    • CTO
    • デリバリー・マネージャー
  • チーム
  • Case Studies
  • ノウハウ
    • ブログ
    • ミートアップ
    • ウェビナー
    • リソース
採用情報 連絡先
戻る矢印 戻る
2021-06-30
ソフトウェア開発

GraphQL Ruby。パフォーマンスについては?

The Codest

トマシュ・シュカラデク

開発アーキテクト

GraphQLには、他のテクノロジーと同様、問題があり、そのいくつかはアーキテクチャに直接起因し、いくつかは他のアプリケーションで見られるものと同じである。しかし、解決策はまったく異なります。

問題を提示するために、次のようなアプリケーション・アーキテクチャを想定してみよう:

https://drive.google.com/file/d/1N4sWPJSls0S8FFHbpHCUVHBNBpEuSsyz/view

対応するクエリは GraphQL をダウンロードしてください。システムに追加されたポスターとそのリンクとともに、すべてのリンクを取得します、

{
  allLinks {
    id
    url
    説明
    作成日時
    投稿日時
      id
      名前
      リンク
        id
      }
    }
  
}

下図のように、典型的なn + 1の問題がここにある。

リンクのロード (0.4ms) SELECT "links".* FROM "links" ORDER BY created_at DESC
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ユーザーロード (0.3ms) SELECT "users".* FROM "users" WHERE "users". "id" = ?LIMIT ?  [["id", 40], ["LIMIT", 1] ]。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'.
  リンクロード (0.3ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 40]] とする。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ユーザーロード (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ?LIMIT ?  [["id", 38], ["LIMIT", 1] ]。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'.
  リンクのロード (0.1ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 38]] とする。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ユーザーロード (0.2ms) SELECT "users".* FROM "users" WHERE "users". "id" = ?LIMIT ?  [["id", 36], ["LIMIT", 1] ]。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  リンクロード (0.1ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 36]] とする。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ユーザーロード (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ?LIMIT ?  [["id", 34], ["LIMIT", 1] ]。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  リンクロード (0.2ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 34]] とする。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ユーザーロード (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ?LIMIT ?  [["id", 32], ["LIMIT", 1]] とする。

この場合、次のように動作する。 コード:
Link.all.map(&:ユーザー).map(&:リンク).

私たちは問題の解決策を知っているようだ: Link.includes(ユーザー: :リンク).map(&:ユーザー).map(&:リンク)しかし、本当に効果があるのだろうか?調べてみよう!

修正を確認するために GraphQL クエリーで、いくつかのフィールドのみを使用し、リレーションは使用しない。

{
  allLinks {
    id
    url
    説明
    作成日時
  }
}

残念ながら、この結果は、ユーザーとそのリンクに関連するリンクがないにもかかわらず、データベースのクエリにこのデータを添付していることを示している。残念なことに、これらは冗長であり、さらに複雑な構造を持つため、単純に非効率であることが判明した。

としてGraphqlController#executeで処理する。
  パラメータ{"query"=>"{n allLinks {n idn urln descriptionn createdAtn }n}"", "graphql"=>{"query"=>"{n allLinks {n idn urln descriptionn createdAtn }n}"}}
  リンクロード (0.3ms) SELECT "links".* FROM "links" ORDER BY created_at DESC
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ) [["id", 40], ["id", 38], ["id", 36], ["id", 34], ["id", 32], ["id", 30], ["id", 28], ["id", 26], ["id", 24], ["id"、22]、["id", 20]、["id", 18]、["id", 16]、["id", 14]、["id", 12]、["id", 10]、["id", 8]、["id", 6]、["id", 4]、["id", 2]] 。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ) [["user_id", 2], ["user_id", 4], ["user_id", 6], ["user_id", 8], ["user_id", 10], ["user_id", 12], ["user_id", 14], ["user_id", 16], ["user_id", 18], ["user_id", 20]、[user_id"、22]、["user_id"、24]、["user_id"、26]、["user_id"、28]、["user_id"、30]、["user_id"、32]、["user_id"、34]、["user_id"、36]、["user_id"、38]、["user_id"、40]]。
  ↳ app/controllers/graphql_controller.rb:5:in `execute'.
39ms で 200 OK を完了 (Views: 0.7ms | ActiveRecord: 0.9ms | Allocations: 8730)

で GraphQLしかし、このような問題は、クエリに入れるときにデータが必要であると仮定して、単純にデータを一括してロードすることで解決される。これが遅延ロードである。最もポピュラーなライブラリのひとつがhttps://github.com/Shopify/graphql-batch/。

残念ながら、そのインストールは手間がかかる。データ・ローダーはこちらで入手できる。https://github.com/Shopify/graphql-batch/tree/master/examples、つまり レコードローダー クラスとアソシエーションローダー クラスをインストールしよう古典的に gem 'graphql-batch' ライブラリを作成し、それをスキーマとローダーに追加する:

# graphql-ruby/app/graphql/graphql_tutorial_schema.rb
class GraphqlTutorialSchema < GraphQL::Schema
  query Types::QueryType
  mutation Types::MutationType
  使用 GraphQL::Batch
  ...
終了

そして私たちのタイプ:

# graphql-ruby/app/graphql/types/link_type.rb
モジュール Types
  クラス LinkType < BaseNode
    field :created_at, DateTimeType, null: false
    field :url, String, null: false
    field :description, String, null: false
    field :posted_by, UserType, null: false, method: :user
    field :votes, [Types::VoteType], null: false

    def user
      Loaders::RecordLoader.for(User).load(object.user_id)
    end
  end
エンド

# graphql-ruby/app/graphql/types/user_type.rb
モジュール Types
  クラス UserType < BaseNode
    field :created_at, DateTimeType, null: false
    field :name, String, null: false
    field :email, String, null: false
    field :votes, [VoteType], null: false
    field :links, [LinkType], null: false

    リンク
      Loaders::AssociationLoader.for(User, :links).load(object)
    end
  end
end

ローダーを使用した結果、データをバッチ化し、2つの単純なSQLクエリーでデータを照会することができる:

2021-06-16 22:40:17 +0200に::1のPOST "/graphql "を開始しました。
   (0.1ms) SELECT sqlite_version(*)
としてGraphqlController#executeで処理。
  パラメータ{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }}", "graphql"=>{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }}"}}".
  リンクロード (0.4ms) SELECT "links".* FROM "links"
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  ) [["id", 2], ["id", 4], ["id", 6], ["id", 8], ["id", 10], ["id", 12], ["id", 14], ["id", 16], ["id", 18], ["id", 20]、[id", 22]、["id", 24]、["id", 26]、["id", 28]、["id", 30]、["id", 32]、["id", 34]、["id", 36]、["id", 38]、["id", 40]] 。
  ↳ app/graphql/loaders/record_loader.rb:12:in `perform'.
  ) [["user_id", 2], ["user_id", 4], ["user_id", 6], ["user_id", 8], ["user_id", 10], ["user_id", 12], ["user_id", 14], ["user_id", 16], ["user_id", 18], ["user_id", 20]、[user_id"、22]、["user_id"、24]、["user_id"、26]、["user_id"、28]、["user_id"、30]、["user_id"、32]、["user_id"、34]、["user_id"、36]、["user_id"、38]、["user_id"、40]]。
  ↳ app/graphql/loaders/association_loader.rb:46:in `preload_association'.
62ms で 200 OK を完了 (Views: 1.3ms | ActiveRecord: 1.8ms | Allocations: 39887)

この問題を解決する解決策は他にもある:

https://github.com/exAspArk/batch-loader#basic-example

クエリーの複雑さ

N+1クエリがすべてではない。 GraphQL の場合、次の属性を自由に引き継ぐことができます。デフォルトでは1に設定されています。これは、特にデータを自由にネストできる状況では、サーバーにとって大きすぎる場合があります。どのように対処すればよいのでしょうか?クエリの複雑さを制限することはできますが、そのためには、属性でコストを指定する必要があります。デフォルトでは1に設定されています。このコストは 複雑さだ: 属性にデータを入力することができる: field: links, [LinkType], null: false, complexity: 101.制限を実際に機能させるのであれば、やはり上限を制度に導入する必要がある:

class GraphqlTutorialSchema < GraphQL::Schema
  query Types::QueryType
  mutation Types::MutationType
  使用 GraphQL::Batch
  最大複雑度 100
  ...
終了

トレース

GraphQL ローカルでできることと比較すると、トレースはそれほど単純ではありません。残念ながら、rack miniのプロファイラや通常のSQLログではすべてを知ることはできませんし、クエリのどの部分が特定のタイムスライスの原因なのかを特定することもできません。GraphQL-Rubyの場合、こちらで入手可能な商用ソリューションを利用することができる: https://graphql-ruby.org/queries/tracingあるいは、独自のトレースを用意することもできる。下のスニペットはローカル・トレーサーのようだ。

# lib/my_custom_tracer.rb
class MyCustomTracer  'graphql.lex'、
    'parse' => 'graphql.parse'、
    'validate' => 'graphql.validate'、
    'analyze_query' => 'graphql.analyze_query'、
    'analyze_multiplex' => 'graphql.analyze_multiplex'、
    'execute_multiplex' => 'graphql.execute_multiplex'、
    'execute_query' => 'graphql.execute_query'、
    'execute_query_lazy' => 'graphql.execute_query_lazy'.
  }

  def platform_trace(platform_key, key, _data, &block)
    start = ::Process.clock_gettime ::Process::CLOCK_MONOTONIC
    result = block.call
    duration = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start
    observe(platform_key, key, duration)
    結果
  終了

  def platform_field_key(type, field)
    "graphql.#{type.graphql_name}.#{field.graphql_name}"
  end

  def platform_authorized_key(type)
    "graphql.authorized.#{type.graphql_name}"
  end

  def platform_resolve_type_key(type)
    "graphql.resolve_type.#{type.graphql_name}"
  end

  def observe(platform_key, key, duration)
    return if key == 'authorized'

    puts "platform_key: #{platform_key}, key: #{key}, duration:#{(duration * 1000).round(5)} ms".yellow
  終了
終了

インストールも非常に簡単で、トレーサー情報をスキーマに含めるだけでよい。 トレーサー (MyCustomTracer.new) コンフィギュレーションを使用します。以下の例のように:

# graphql-ruby/app/graphql/graphql_tutorial_schema.rb
class GraphqlTutorialSchema < GraphQL::Schema
  query Types::QueryType
  mutation Types::MutationType
  use GraphQL::Batch
  トレーサー(MyCustomTracer.new)
  ...
終了

このようなトレースからの出力は次のようになる:

2021-06-17 22:02:44 +0200に::1のPOST "/graphql "を開始しました。
   (0.1ms) SELECT sqlite_version(*)
としてGraphqlController#executeで処理。
  パラメータパラメータ:{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }}", "graphql"=>{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }}" }}。
platform_key: graphql.lex, key: lex, duration:0.156 ms
platform_key: graphql.parse, key: parse, duration:0.108 ms
platform_key: graphql.validate、キー: validate、継続時間: 0.537 ms0.537 ms
platform_key: graphql.analyze_query、キー: analyze_query、継続時間: 0.123 ms0.123 ms
platform_key: graphql.analyze_multiplex、キー: analyze_multiplex、継続時間: 0.159 ms0.159ms
  リンクロード (0.4ms) SELECT "links".* FROM "links"
  ↳ app/graphql/graphql_tutorial_schema.rb:21:in `platform_trace'
platform_key: graphql.execute_query, key: execute_query, duration:15.562 ms
  ↳ app/graphql/loaders/record_loader.rb:12:in `perform'.
  ↳ app/graphql/loaders/association_loader.rb:46:in `preload_association'
platform_key: graphql.execute_query_lazy, key: execute_query_lazy, duration:14.12 ms
platform_key: graphql.execute_multiplex, key: execute_multiplex, duration:31.11 ms
200 OK を 48ms で完了 (Views: 1.2ms | ActiveRecord: 2.0ms | Allocations: 40128)

概要

GraphQL はもう新しい技術ではないが、その問題に対する解決策は、図書館の一部でなければ完全には標準化されない。この技術を プロジェクト 個人的には、REST APIが提供するものとの関連で、これは新しい品質だと考えている。

おそらく)Typescriptを使うべき理由

悪いコーディング・プラクティスでプロジェクトを潰さないためには?

NextJSのデータフェッチ戦略

関連記事

ソフトウェア開発

将来を見据えたウェブ・アプリケーションの構築:The Codestのエキスパート・チームによる洞察

The Codestが、最先端技術を駆使してスケーラブルでインタラクティブなウェブアプリケーションを作成し、あらゆるプラットフォームでシームレスなユーザー体験を提供することにどのように秀でているかをご覧ください。The Codestの専門知識がどのようにデジタルトランスフォーメーションとビジネス...

ザ・コデスト
ソフトウェア開発

ラトビアを拠点とするソフトウェア開発企業トップ10社

ラトビアのトップソフトウェア開発企業とその革新的なソリューションについて、最新記事でご紹介します。ラトビアの技術リーダーたちがあなたのビジネスをどのように向上させるかをご覧ください。

thecodest
エンタープライズ&スケールアップ・ソリューション

Javaソフトウェア開発の要点:アウトソーシングを成功させるためのガイド

outsourcingのJavaソフトウェア開発を成功させるために不可欠なこのガイドを読んで、The Codestで効率性を高め、専門知識にアクセスし、プロジェクトを成功に導きましょう。

thecodest
ソフトウェア開発

ポーランドにおけるアウトソーシングの究極ガイド

ポーランドのoutsourcingの急増は、経済、教育、技術の進歩がITの成長とビジネス・フレンドリーな環境を促進していることによる。

ザ・コデスト
エンタープライズ&スケールアップ・ソリューション

IT監査ツール&テクニック完全ガイド

IT監査は、安全かつ効率的で、コンプライアンスに準拠したシステムを保証します。その重要性については、記事全文をお読みください。

The Codest
ヤクブ・ヤクボヴィッチ CTO & 共同創設者

ナレッジベースを購読して、IT部門の専門知識を常に最新の状態に保ちましょう。

    会社概要

    The Codest - ポーランドに技術拠点を持つ国際的なソフトウェア開発会社。

    イギリス - 本社

    • オフィス 303B, 182-184 High Street North E6 2JA
      イギリス、ロンドン

    ポーランド - ローカル・テック・ハブ

    • ファブリチュナ・オフィスパーク、アレハ
      ポコジュ18、31-564クラクフ
    • ブレイン・エンバシー, コンストルクトースカ
      11, 02-673 Warsaw, Poland

      The Codest

    • ホーム
    • 会社概要
    • サービス
    • Case Studies
    • ノウハウ
    • 採用情報
    • 辞書

      サービス

    • アドバイザリー
    • ソフトウェア開発
    • バックエンド開発
    • フロントエンド開発
    • Staff Augmentation
    • バックエンド開発者
    • クラウドエンジニア
    • データエンジニア
    • その他
    • QAエンジニア

      リソース

    • 外部ソフトウェア開発パートナーとの協力に関する事実と神話
    • 米国から欧州へ:アメリカの新興企業がヨーロッパへの移転を決断する理由
    • テックオフショア開発ハブの比較:テックオフショア ヨーロッパ(ポーランド)、ASEAN(フィリピン)、ユーラシア(トルコ)
    • CTOとCIOの課題は?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • ウェブサイト利用規約

    著作権 © 2025 by The Codest。無断複写・転載を禁じます。

    jaJapanese
    en_USEnglish de_DEGerman sv_SESwedish da_DKDanish nb_NONorwegian fiFinnish fr_FRFrench pl_PLPolish arArabic it_ITItalian ko_KRKorean es_ESSpanish nl_NLDutch etEstonian elGreek jaJapanese