Skip to content

[GraphQL] Aim to reduce N+1 queries

In our GraphQL we could make better use of the Query to avoid N+1 queries. The key to this is making use of lookahead

Example

The following query shows where we could avoid extra queries:

query {
    project(fullPath: "gitlab-org/gitlab") {
        mergeRequests(first: 10) {
            author {
                username
            }
            assignees {
                nodes { username }
            }
        }
    }
}

In this query, we will execute it as follows (simplified)

  • find the project by full path (1 query)
  • find the first 10 merge requests (1 query)
  • for each merge request:
    • find the author (1 query)
    • find the assignees (1 query)

For a total of 22 queries.

The optimal solution would be something like:

  • find the project by full path (1 query)
  • find the first 10 merge requests (1 query)
  • Find the union of assignees and author for the MRs (1 query)

But the low hanging fruit is to use the fact that the query tells us up-front that we will need author and assignees and use #preload(:author, :assignees) to reduce this to 4 queries, and eliminate the N + 1 complexity.

Very few (if any) of our resolvers perform this kind of lookahead optimization, but it could have a significant ~performance impact, especially for large collections that we expect to be retrieved, such as merge requests, issues, pipeline jobs, etc.

Edited by Alex Kalderimis