One of the most important pain points in GraphQL is the problem thats commonly referred to as N+1 SQL queries. GraphQL query fields are designed to be stand-alone functions, and resolving those fields with data from a database might result in a new database request per resolved field.
For a simple RESTful API endpoint logic, it’s easy to analyze, detect, and solve N+1 issues by enhancing the constructed SQL queries. For GraphQL dynamically resolved fields, it’s not that simple.
For example, Consider the GraphQL query to fetch article, its comments and commented user which I mentioned in previous post.
{"data":{"acticle":{"title":"A GraphQL Server","comments":[{"comment":"Good article","user":{"id":1,"name":"Shaiju E"}},{"comment":"Keep going","user":{"id":1,"name":"Shaiju E"}},{"comment":"Another Comment","user":{"id":2,"name":"David"}},{"comment":"New Comment","user":{"id":1,"name":"Shaiju E"}},{"comment":"Another Comment from User 2","user":{"id":2,"name":"David"}},{"comment":"Another Comment from User 1","user":{"id":1,"name":"Shaiju E"}},{"comment":"TEST","user":{"id":1,"name":"Shaiju E"}}]}}}
This will fire user query in for each comment. Total 7 instead of 1 for fetch 2 user. In Rest API we can solve this issue by eager loading users while fetching comments. But GraphQL query fields are designed to be stand-alone functions, and not aware of other functions.
Facebook introduced DataLoader to solve this problem in Javascript projects. Shopify created GraphQL::Batch to solve this N+1 problem in ruby. GraphQL::Batch Provides an executor for the graphql gem which allows queries to be batched. This is a flexible toolkit for lazy resolution with GraphQL.
Installation
1
gem'graphql-batch'
Now we need to define a custom loader, which is initialized with arguments that are used for grouping and a perform method for performing the batch load.
Here, resolve -> (obj, args, ctx) {RecordLoader.for(User).load(obj.user_id) } will make user fetching lazy loading there by solve N+1 query problem.
Before:
After
More information about GraphQL::Batch is available in Gem Documentation
You can see sample code here.