Skip to main content
Version: 5.0

Query plan

The problem

GraphQL naive implementations often suffer from the "N+1" problem.

Let's have a look at the following query:

{
products {
name
manufacturer {
name
}
}
}

A naive implementation will do this:

  • 1 query to fetch the list of products
  • 1 query per product to fetch the manufacturer

Assuming we have "N" products, we will make "N+1" queries.

There are several ways to fix this problem. Assuming you are using a relational database, one solution is to try to look ahead and perform only one query with a JOIN between "products" and "manufacturers".

But how do I know if I should make the JOIN between "products" and "manufacturers" or not? I need to know ahead of time.

With GraphQLite, you can answer this question by tapping into the ResolveInfo object.

Fetching the query plan

Available in GraphQLite 4.0+
use GraphQL\Type\Definition\ResolveInfo;

class ProductsController
{
/**
* @return Product[]
*/
#[Query]
public function products(ResolveInfo $info): array
{
if (isset($info->getFieldSelection()['manufacturer']) {
// Let's perform a request with a JOIN on manufacturer
} else {
// Let's perform a request without a JOIN on manufacturer
}
// ...
}
}

ResolveInfo is a class provided by Webonyx/GraphQL-PHP (the low-level GraphQL library used by GraphQLite). It contains info about the query and what fields are requested. Using ResolveInfo::getFieldSelection you can analyze the query and decide whether you should perform additional "JOINS" in your query or not.

As of the writing of this documentation, the ResolveInfo class is useful but somewhat limited. The next version of Webonyx/GraphQL-PHP will add a "query plan"that allows a deeper analysis of the query.