Solving the N+1 Problem in GraphQL

The N+1 problem occurs when we use data returned from the database to fuel a list of further queries to the database.

Article title image. Solving the N+1 Problem in GraphQL

Meaning, if you receive a list of results from a query, then for each result, you will make another query to the database.

In this case, the N stands for the number of results returned from the database, and 1 stands for the initial query that was made.

To clarify: the problem is that for each of the N results returned, we will have to make another query, so there will be N requests made to the database, plus the 1, which was the initial request.

This can easily become a performance bottleneck.

Example of an N+1 Situation

You want to query the grades for all the students who go to a school. The N+1 problem would occur if you first queried all the students who go to that school, and then made a loop that would query the grades for each student that was returned, one at a time.

Here’s some example pseudocode:

const students = `SELECT * FROM students`students.forEach(student => 
`SELECT * FROM grades WHERE student_id = ${student.student_id}`)

Traditional Solution for the N+1 Problem

The generally accepted solution is to batch you requests. Meaning, you make a list of the ID’s of the results from the initial request, and then your second request gets dynamically populated with this list. This solution reduces the number of requests to the database from N+1 to only 2.

Example pseudocode:

const students = `SELECT * FROM students`const studentIds = students.map(student => student.student_id)const grades = `SELECT * FROM grades WHERE student_id IN ${studentIds}`

To clarify: in the code above, we first query all of the students, then make a list (aka array) of all their ID’s. Then we make a query to the database for all the grades, but also supply it with our list of Student ID’s, and ask the database to filter the results for us by those ID’s.

Now that’s a lot more performant!

Why This Solution Doesn’t Work With GraphQL

The generally accepted implementation of GraphQL is Apollo, which uses Resolvers. Each resolver only has access to the the return value of its parent, meaning that you can’t go and make a list of ID’s like we did above, and then supply them to a batched query.

So how do we solve this? We use a package called DataLoader.

How to Solve the N+1 Problems in GraphQL

DataLoader is a package that batches object loads from the data store. It also has a memoization cache, which prevents our app from loading the same object multiple times from a single GraphQL request. It also enables us to fetch multiple objects at once via a batching operation, which avoids the N+1 problem.

In a future article, I’ll do an in-depth dive into how to implement DataLoader in your GraphQL project.

If you enjoyed this article, please give it a clap! 👏🏼 Claps make me happy ;)

I’m a Front End Engineer who loves React, NextJS, and GraphQL. Need a REMOTE React Developer? Contact me at: https://www.linkedin.com/in/bengrunfeld/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store