Skip to content

Schema::Visibility is much slower than Schema::Warden #5324

Closed
@myronmarston

Description

@myronmarston

Describe the bug

I've been working on deploying an upgrade to one of our internal systems, and discovered that using GraphQL::Schema::Visibility is much slower than the GraphQL::Schema::Warden plugin that we've been using. According to my benchmark, it's more than 20x slower for a very simple query!

Versions

graphql version: 2.5.2
rails (or other framework): N/A
other applicable versions (graphql-batch, etc): N/A

GraphQL schema

https://gist.github.com/myronmarston/ee6fa2d92d2941b7071459708f7d46d1

(Apologies for the large anonymized schema, but I didn't think I should share our proprietary internal schema and I wasn't able to come up with a smaller schema that reproduced this issue--so I just replaced all the type names and field names to anonymize it.).

GraphQL query

  query {
    field264(
      field265: [ENUM_VALUE1000]
    ) {
      __typename
    }
  }

Steps to reproduce

Create a ruby script with this code:

require "bundler/inline"

gemfile do
  source "https://rubygems.org"

  gem "graphql", "2.5.2"
  gem "benchmark-ips"
end

require "benchmark/ips"
require "graphql"
require "open-uri"

SCHEMA_STRING = URI("https://gist.githubusercontent.com/myronmarston/ee6fa2d92d2941b7071459708f7d46d1/raw/8b99a4d9723dc99a7a921cf787c8e6b31a8fc6b7/anonymized_schema.graphql").read

class Application
  def initialize(using: {})
    @schema = ::GraphQL::Schema.from_definition(
      SCHEMA_STRING,
      default_resolve: self,
      using: using
    )
  end

  def call(parent_type, field, object, args, context)
    nil
  end

  def execute_query(query_string)
    response = ::GraphQL::Query.new(@schema, query_string, variables: {}).result

    unless response.fetch("errors", []).empty?
      raise "Query failed: #{response.to_h.inspect}"
    end

    response
  end
end

warden_app = Application.new(using: {
  GraphQL::Schema::Warden => {}
})

visibility_app = Application.new(using: {
  GraphQL::Schema::Visibility => {preload: true}
})

query = <<~EOS
  query {
    field264(
      field265: [ENUM_VALUE1000]
    ) {
      __typename
    }
  }
EOS

Benchmark.ips do |x|
  x.report("Using Visibility") do
    visibility_app.execute_query(query)
  end

  x.report("Using Warden") do
    warden_app.execute_query(query)
  end

  x.compare!
end

Run it.

Expected behavior

I expect the new GraphQL::Schema::Visibility plugin to be as performant as GraphQL::Schema::Warden. (At least, I need it to be as performant before I can switch to the new plugin, and I'm expecting Warden to be removed in a future version.)

Actual behavior

The Visibility plugin is ~20x slower:

ruby 3.2.7 (2025-02-04 revision 02ec315244) [arm64-darwin24]
Warming up --------------------------------------
    Using Visibility    13.000 i/100ms
        Using Warden   253.000 i/100ms
Calculating -------------------------------------
    Using Visibility    127.969 (± 0.8%) i/s    (7.81 ms/i) -    650.000 in   5.079653s
        Using Warden      2.742k (± 2.8%) i/s  (364.70 μs/i) -     13.915k in   5.079058s

Comparison:
        Using Warden:     2742.0 i/s
    Using Visibility:      128.0 i/s - 21.43x  slower

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions