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.
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.