2021-01-22
GraphQL Rubyで書かれたサーバーで、edges.node
を使って問い合わせるよりもnodes
を使って問い合わせたほうが速い、しかもそこそこの差が出る、ということを知った。
require 'graphql' module Types class PostType < GraphQL::Schema::Object description "A blog post" field :id, ID, null: false field :title, String, null: false end end Post = Struct.new(:id, :title, keyword_init: true) Posts = 10000.times.map { |i| Post.new(id: i.to_s, title: "foo #{i}") } class QueryType < GraphQL::Schema::Object description "The query root of this schema" field :posts, Types::PostType.connection_type, null: false def posts Posts end end class Schema < GraphQL::Schema query QueryType end edges_node = -> (first:) do Schema.execute(<<~Q, variables: { first: first }) query Q($first: Int!) { posts(first: $first) { edges { node { id title } } } } Q end nodes = -> (first:) do Schema.execute(<<~Q, variables: { first: first }) query Q($first: Int!) { posts(first: $first) { nodes { id title } } } Q end require 'benchmark' Benchmark.bmbm(20) do |x| x.report('edges.node - 10') {3000.times{ edges_node.(first: 10) }} x.report('nodes - 10') {3000.times{ nodes.(first: 10) }} x.report('edges.node - 100') {1000.times{ edges_node.(first: 100) }} x.report('nodes - 100') {1000.times{ nodes.(first: 100) }} x.report('edges.node - 10000') {10.times{ edges_node.(first: 10000) }} x.report('nodes - 10000') {10.times{ nodes.(first: 10000) }} end
$ ruby bench.rb Rehearsal -------------------------------------------------------- edges.node - 10 2.735607 0.000000 2.735607 ( 2.739255) nodes - 10 2.132201 0.000000 2.132201 ( 2.134951) edges.node - 100 3.924149 0.000000 3.924149 ( 3.929026) nodes - 100 2.454493 0.000000 2.454493 ( 2.457573) edges.node - 10000 3.625352 0.023201 3.648553 ( 3.651399) nodes - 10000 1.998549 0.000000 1.998549 ( 2.000025) ---------------------------------------------- total: 16.893552sec user system total real edges.node - 10 2.766556 0.000000 2.766556 ( 2.770303) nodes - 10 2.148939 0.000000 2.148939 ( 2.152065) edges.node - 100 3.837464 0.000000 3.837464 ( 3.842603) nodes - 100 2.441282 0.000000 2.441282 ( 2.444682) edges.node - 10000 3.562626 0.003326 3.565952 ( 3.568947) nodes - 10000 1.973643 0.000000 1.973643 ( 1.975118)
first
が10の時に1.29倍、100の時に1.57倍、10000の時に1.81倍ぐらいの差がある。
これは適当な例だけど、手元のRails appでActive RecordでDBからレコードを引いてくるようなケースでも、件数によって1.1 ~ 1.3倍ぐらいの速度改善ができた。 もっとDBが支配的だと思っていたから、ここまでGraphQL Ruby側の影響が大きいのかーとびっくり。
単にオブジェクトの生成数が減るのと、GraphQL Rubyが各Nodeに色々やる処理のオーバーヘッドが減るのが大きいのかなあ。