window.pipedriveLeadboosterConfig = { base: leadbooster-chat.pipedrive.com', companyId: 11580370, playbookUuid: '22236db1-6d50-40c4-b48f-8b11262155be', version: 2, } ;(function () { var w = window if (w.LeadBooster) { console.warn('LeadBooster on juba olemas') } else { w.LeadBooster = { q: [], on: function (n, h) { this.q.push({ t: 'o', n: n, h: h }) }, trigger: function (n) { this.q.push({ t: 't', n: n }) }, } } })() GraphQL Ruby. Kuidas on tulemuslikkus? - The Codest
The Codest
  • Meie kohta
  • Teenused
    • Tarkvaraarendus
      • Frontend arendus
      • Backend arendus
    • Staff Augmentation
      • Frontend arendajad
      • Backend arendajad
      • Andmeinsenerid
      • Pilveinsenerid
      • QA insenerid
      • Muud
    • See nõuandev
      • Audit ja nõustamine
  • Tööstusharud
    • Fintech & pangandus
    • E-commerce
    • Adtech
    • Healthtech
    • Tootmine
    • Logistika
    • Autotööstus
    • IOT
  • Väärtus
    • CEO
    • CTO
    • Tarnejuht
  • Meie meeskond
  • Case Studies
  • Tea kuidas
    • Blogi
    • Kohtumised
    • Veebiseminarid
    • Ressursid
Karjäärivõimalused Võtke ühendust
  • Meie kohta
  • Teenused
    • Tarkvaraarendus
      • Frontend arendus
      • Backend arendus
    • Staff Augmentation
      • Frontend arendajad
      • Backend arendajad
      • Andmeinsenerid
      • Pilveinsenerid
      • QA insenerid
      • Muud
    • See nõuandev
      • Audit ja nõustamine
  • Väärtus
    • CEO
    • CTO
    • Tarnejuht
  • Meie meeskond
  • Case Studies
  • Tea kuidas
    • Blogi
    • Kohtumised
    • Veebiseminarid
    • Ressursid
Karjäärivõimalused Võtke ühendust
Tagasi nool TAGASI
2021-06-30
Tarkvaraarendus

GraphQL Ruby. Kuidas on tulemuslikkus?

The Codest

Tomasz Szkaradek

Arendusarhitekt

GraphQLil, nagu igal tehnoloogial, on omad probleemid, millest mõned tulenevad otseselt arhitektuurist ja mõned on identsed sellega, mida me näeme mis tahes muu rakenduse puhul. Lahendused on aga täiesti erinevad.

Probleemi tutvustamiseks oletame, et rakenduse arhitektuur on järgmine:

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

Ja siin on vastav päring GraphQL andmete allalaadimiseks. Me toome kõik lingid koos plakatiga ja selle lingid lisatakse süsteemi,

{
  allLinks {
    id
    url
    description
    createdAt
    postedBy {
      id
      name
      lingid {
        id
      }
    }
  }
}

Nagu allpool näidatud, näeme siin klassikalist n + 1 suhetega probleemi.

Linkide laadimine (0.4ms) SELECT "links".* FROM "links" ORDER BY created_at DESC
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users". "id" = ? LIMIT ?  [["id", 40], ["LIMIT", 1]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Linkide laadimine (0.3ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 40]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ? LIMIT ?  [["id", 38], ["LIMIT", 1]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Linkide laadimine (0.1ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 38]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Kasutajate laadimine (0.2ms) SELECT "users".* FROM "users" WHERE "users". "id" = ? LIMIT ?  [["id", 36], ["LIMIT", 1]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Linkide laadimine (0.1ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 36]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Kasutajate laadimine (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ? LIMIT ?  [["id", 34], ["LIMIT", 1]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Linkide laadimine (0.2ms) SELECT "links".* FROM "links" WHERE "links". "user_id" = ?  [["user_id", 34]]
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  User Load (0.1ms) SELECT "users".* FROM "users" WHERE "users". "id" = ? LIMIT ?  [["id", 32], ["LIMIT", 1]]

Sellisel juhul töötab see täpselt nagu see tükk kood:
Link.all.map(&:user).map(&:links).

Tundub, et me teame probleemi lahendust: Link.includes(user: :links).map(&:user).map(&:links), kuid kas see tõesti toimib? Kontrollime seda!

Selleks, et kontrollida parandust, muutsin ma GraphQL päring, et kasutada ainult mõnda välja ja mingit seost.

{
  allLinks {
    id
    url
    description
    createdAt
  }
}

Kahjuks näitab tulemus, et hoolimata linkide puudumisest seoses kasutaja ja nende linkidega, lisame need andmed ikkagi andmebaasi päringule. Kahjuks on need üleliigsed ja veelgi keerulisema struktuuri puhul osutub see lihtsalt ebaefektiivseks.

Töötlemine GraphqlController#execute abil */*
  Parameetrid: {"query"=>"{n allLinks {n idn urln descriptionn createdAtn }n}", "graphql"=>{{"query"=>"{n allLinks {n idn urln descriptionn createdAtn }n}"}}
  Linkide laadimine (0.3ms) SELECT "links".* FROM "links" ORDER BY created_at DESC
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  User Load (0.3ms) SELECT "users".* FROM "users" WHERE "users". "id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ??) [["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'
  Linkide laadimine (0.3ms) SELECT "links".* FROM "links" WHERE "links". "user_id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ??) [["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'
Lõpetas 200 OK 39ms jooksul (Views: 0.7ms | ActiveRecord: 0.9ms | Allocations: 8730)

Veebilehel GraphQL, lahendatakse sellised probleemid teisiti,lihtsalt laadides andmeid partiidena, eeldades, et andmeid on vaja siis, kui need päringusse pannakse. See on selline laisk laadimine. Üks populaarsemaid raamatukogusid on https://github.com/Shopify/graphql-batch/.

Kahjuks ei ole selle paigaldamine nii lihtne, kui see võib tunduda. Andmete laadijad on saadaval siin: https://github.com/Shopify/graphql-batch/tree/master/examples, ma mõtlen RecordLoader klassi jaAssociationLoader klass. Paigaldame klassikaliselt gem 'graphql-batch' raamatukogu ja seejärel lisame selle meie skeemi, samuti laadijad:

# graphql-ruby/app/graphql/graphql_tutorial_schema.rb
class GraphqlTutorialSchema < GraphQL::Schema
  query Types::QueryType
  mutation Types::MutationType
  use GraphQL::Batch
  ...
end

Ja meie tüübid:

# graphql-ruby/app/graphql/types/link_type.rb
moodul Tüübid
  class LinkType < BaseNode
    field :created_at, DateTimeType, null: false
    field :url, String, null: false
    field :description, String, null: false
    väli :posted_by, UserType, null: false, meetod: :user
    field :votes, [Types::VoteType], null: false

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

# graphql-ruby/app/graphql/types/user_type.rb
moodul Tüübid
  class UserType < BaseNode
    väli :created_at, DateTimeType, null: false
    väli :name, String, null: false
    field :email, String, null: false
    väli :votes, [VoteType], null: false
    field :links, [LinkType], null: false

    def links
      Loaders::AssociationLoader.for(User, :links).load(object)
    end
  end
end

Laadijate kasutamise tulemusena pakime andmeid partiidena ja küsime andmeid kahe lihtsa sql päringuga:

Käivitati POST "/graphql" jaoks ::1 kell 2021-06-16 22:40:17 +0200
   (0.1ms) SELECT sqlite_version(*)
Töötlemine GraphqlController#ulemusena */*
  Parameetrid: {"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }n}", "graphql"=>{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }n }n}"}}
  Linkide laadimine (0.4ms) SELECT "lingid".* FROM "lingid"
  ↳ app/controllers/graphql_controller.rb:5:in `execute'
  Kasutajate laadimine (0.9ms) SELECT "users".* FROM "users" WHERE "users". "id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ??) [["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'
  Linkide laadimine (0.5ms) SELECT "links".* FROM "links" WHERE "links". "user_id" IN (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ??) [["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'
Lõpetas 200 OK 62ms jooksul (Views: 1.3ms | ActiveRecord: 1.8ms | Allocations: 39887)

On ka teisi lahendusi, mis lahendavad selle probleemi, näiteks:

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

Päringute keerukus

N + 1 päringud ei ole kõik, in GraphQL saame vabalt kanda üle järgmised atribuudid. Vaikimisi on see seatud 1. See võib mõnikord olla serverile liiga palju, eriti olukorras, kus me saame andmeid vabalt pesitseda. Kuidas sellega toime tulla? Me saame piirata päringu keerukust, kuid selleks peame määrama ka nende maksumuse atribuutides. Vaikimisi on see määratud 1. Me määrame selle kulu, kasutades keerukus: atribuut, kuhu me saame sisestada andmeid: field: links, [LinkType], null: false, complexity: 101. Kui piiramine peaks tegelikult toimima, peate ikkagi kehtestama oma skeemi maksimumpiiri:

class GraphqlTutorialSchema < GraphQL::Schema
  päring Tüübid::QueryType
  mutation Types::MutationType
  use GraphQL::Batch
  max_complexity 100
  ...
end

Jälgimine

GraphQL töötleb päringuid erinevalt ja jälgimine ei ole nii lihtne, kui võrrelda seda sellega, mida me saame teha kohapeal. Kahjuks ei ütle rack mini profiler või tavaline SQL log meile kõike ja ei osuta, milline osa päringust on vastutav antud ajaviilu eest. GraphQL-Ruby puhul saame kasutada siin kättesaadavaid kommertslahendusi: https://graphql-ruby.org/queries/tracing, või püüda valmistada ise oma jälgimist. Järgnevalt näeb see lõik välja nagu kohalik tracer.

# 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' => '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)
    tulemus
  end

  def platform_field_key(type, field)
    "graphql.#{tüüp.graphql_nimi}.#{välja.graphql_nimi}"
  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: #{(kestus * 1000).round(5)} ms".yellow
  end
end

Paigaldamine on samuti väga lihtne, peate lisama jälgimisseadme andmed skeemi tracer (MyCustomTracer.new) konfiguratsioon. Nagu alljärgnevas näites:

# graphql-ruby/app/graphql/graphql_tutorial_schema.rb
class GraphqlTutorialSchema < GraphQL::Schema
  query Types::QueryType
  mutation Types::MutationType
  use GraphQL::Batch
  tracer(MyCustomTracer.new)
  ...
end

Sellise jälgimise väljund näeb välja selline:

Käivitati POST "/graphql" jaoks ::1 kell 2021-06-17 22:02:44 +0200
   (0.1ms) SELECT sqlite_version(*)
Töötlemine GraphqlController#ulemusena */*
  Parameetrid: {"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }n}", "graphql"=>{"query"=>"{n allLinks {n idn urln descriptionn createdAtn postedBy {n idn namen links {n idn }n }n }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, key: validate, duration: 0.537 ms
platform_key: graphql.analyze_query, võti: analyze_query, kestus: 0.123 ms
platform_key: graphql.analyze_multiplex, key: analyze_multiplex, duration: 0.159 ms
  Linkide koormus (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
Lõpetatud 200 OK 48 ms jooksul (Vaated: 1.2ms | ActiveRecord: 2.0ms | Allocations: 40128)

Kokkuvõte

GraphQL ei ole enam uus tehnoloogia, kuid selle probleemide lahendused ei ole täielikult standardiseeritud, kui need ei ole osa raamatukogust. Selle tehnoloogia rakendamise projekt annab palju võimalusi frontendiga suhtlemiseks ja mina isiklikult pean seda uueks kvaliteediks võrreldes sellega, mida REST API pakub.

Miks peaksite (tõenäoliselt) kasutama Typescript'i

Kuidas mitte tappa projekti halbade kodeerimistavadega?

NextJS-i andmete hankimise strateegiad

Seotud artiklid

Tarkvaraarendus

Tulevikukindlate veebirakenduste loomine: The Codest ekspertide meeskonna ülevaade

Avastage, kuidas The Codest paistab skaleeritavate, interaktiivsete veebirakenduste loomisel silma tipptehnoloogiatega, mis pakuvad sujuvat kasutajakogemust kõigil platvormidel. Saate teada, kuidas meie eksperditeadmised aitavad kaasa digitaalsele ümberkujundamisele ja äritegevusele...

THECODEST
Tarkvaraarendus

Top 10 Lätis asuvat tarkvaraarendusettevõtet

Tutvu Läti parimate tarkvaraarendusettevõtete ja nende innovaatiliste lahendustega meie viimases artiklis. Avastage, kuidas need tehnoloogiajuhid saavad aidata teie äri edendada.

thecodest
Enterprise & Scaleups lahendused

Java tarkvaraarenduse põhitõed: A Guide to Outsourcing Successfully

Tutvuge selle olulise juhendiga, kuidas edukalt outsourcing Java tarkvara arendada, et suurendada tõhusust, pääseda ligi eksperditeadmistele ja edendada projekti edu The Codest abil.

thecodest
Tarkvaraarendus

Ülim juhend Poola allhanke kohta

outsourcing kasv Poolas on tingitud majanduslikust, hariduslikust ja tehnoloogilisest arengust, mis soodustab IT kasvu ja ettevõtlussõbralikku kliimat.

TheCodest
Enterprise & Scaleups lahendused

Täielik juhend IT-auditi vahendite ja tehnikate kohta

IT-auditid tagavad turvalised, tõhusad ja nõuetele vastavad süsteemid. Lisateavet nende tähtsuse kohta leiate kogu artiklist.

The Codest
Jakub Jakubowicz CTO & kaasasutajad

Tellige meie teadmistebaas ja jääge kursis IT-sektori eksperditeadmistega.

    Meie kohta

    The Codest - rahvusvaheline tarkvaraarendusettevõte, mille tehnoloogiakeskused asuvad Poolas.

    Ühendkuningriik - peakorter

    • Büroo 303B, 182-184 High Street North E6 2JA
      London, Inglismaa

    Poola - kohalikud tehnoloogiakeskused

    • Fabryczna büroopark, Aleja
      Pokoju 18, 31-564 Kraków
    • Brain Embassy, Konstruktorska
      11, 02-673 Varssavi, Poola

      The Codest

    • Kodu
    • Meie kohta
    • Teenused
    • Case Studies
    • Tea kuidas
    • Karjäärivõimalused
    • Sõnastik

      Teenused

    • See nõuandev
    • Tarkvaraarendus
    • Backend arendus
    • Frontend arendus
    • Staff Augmentation
    • Backend arendajad
    • Pilveinsenerid
    • Andmeinsenerid
    • Muud
    • QA insenerid

      Ressursid

    • Faktid ja müüdid koostööst välise tarkvaraarenduspartneriga
    • USAst Euroopasse: Miks otsustavad Ameerika idufirmad Euroopasse ümber asuda?
    • Tech Offshore arenduskeskuste võrdlus: Euroopa (Poola), ASEAN (Filipiinid), Euraasia (Türgi).
    • Millised on CTO ja CIOde peamised väljakutsed?
    • The Codest
    • The Codest
    • The Codest
    • Privacy policy
    • Website terms of use

    Copyright © 2025 by The Codest. Kõik õigused kaitstud.

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