-
-
Notifications
You must be signed in to change notification settings - Fork 724
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Query Execution Plans #677
Comments
Tasks:
|
public interface IExecutionTask
{
Task InvokeAsync(IExecutionContext context);
}
public class ExecuteInParallel
{
public IReadOnlyList<IExecutionTask> Tasks { get; }
...
}
public class ExecuteResolver
{
public IResolverContext { get; }
public FieldResolverDelegate Resolver { get; }
...
}
public interface IFieldInfo
{
ObjectField Field { get; }
FieldNode FieldSelection { get; }
IReadOnlyList<...> Dependencies { get; }
} |
Query Execution PlansWe are thinking about introducing query execution plans for quite a while now. We think we can benefit from execution plans in the following areas:
Our aim is that the execution plans are extendible so that one can write its own execution tasks that is able to optimize execution further or bring new capabilities to it. Analysing QueriesIn order to be able to optimize queries we need to know what a resolver does, and currently this can be challenging. In code-first some resolvers are pretty good to analyse. public async Task<Person> GetPersonAsync(string id, [DataLoader]IPersonDataLoader dataLoader)
{
...
} Form the above example we know that the resolver takes the We could now pool these resolvers and execute all of them in one go. What if we could even go further and give the analyzer more hints like the following: type Query {
person(id: ID! @field(type: "Person" field: "id")) : Person
} In the above example we are now exposing that the argument passed into the resolver is actually the id of the person. If a resolver depends on data of person an exoses that. type Person {
id: ID!
name: String!
bestFriend: Person! @dependsOn(type: "Person" field: "id")
friends: [Person!]
} The query engine could optimize the following request: {
person(id: "123")
{
name
bestFriend {
name
}
}
} The optimized request could look like the following if written in graphQL: {
person(id: "123")
{
name
}
bestFriend(friendId: "123") {
name
}
} So, we could actually fetch both information in parallel and then assemble results afterwards. WORK IN PROGRESS |
Just as a reminder for myself:
|
This is implemented. |
The current implementation of the execution engine executes field batches. Each field batch represents a query level. For features like @defer and stitching it would be better if we could provide the execution with an execution plan that defines how the query should be best executed. Instead of batches the query could process fields more like a stream where parts that are ready to be processed will pulled in as other fields are finished off.
The text was updated successfully, but these errors were encountered: