-
Notifications
You must be signed in to change notification settings - Fork 3.2k
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: Prevent client evaluation and N+1 queries when calling result operators before other operators #6611
Comments
Initially when the query is parsed, each Include call is treated as result operator, effectively producing a subquery, unless it's the last operation, e.g.:
translates to:
in the next step we extract the include operators out of the query:
and then we remove redundant subqueries:
However, if there is orderby before the include
we get a more complicated query:
We extract include operators, but we can't remove the additional subquery it generated because of the orderby:
|
Perhaps, this could be improved for some cases by lifting orderby out of the subquery into the main query:
could be translated into:
and then subquery could be optimized out:
If the outer query has an orderby:
we could do something like this (append inner ordeby to the end of the outer one):
Question is what should we do when there are multiple subqueries due to joins or few levels of subqueries |
reassigning to Smit as he is working on a similar issue |
poaching this |
…en Include then Where to a one to many relationship Problem was that during initial parsing of query model, Include, AsTracking, AsNoTracking force subqueries to be created (since they are result operators). Those operators are then removed, but the subqueries persist, making it much harder to translate queries efficiently. We try to prune "empty" subqueries, but sometimes it is safe to lift subqueries that contain body clauses. Fix is to recognize those patterns and perform the lift during query model optimizations. We do it for cases when the subquery is coming from the MainFromClause, it doesn't contain any result operators and is projecting it's MainFromClause only in the selector. The optimization is the most prominent for queries with Include but will help other cases also.
…en Include then Where to a one to many relationship Problem was that during initial parsing of query model, Include, AsTracking, AsNoTracking force subqueries to be created (since they are result operators). Those operators are then removed, but the subqueries persist, making it much harder to translate queries efficiently. We try to prune "empty" subqueries, but sometimes it is safe to lift subqueries that contain body clauses. Fix is to recognize those patterns and perform the lift during query model optimizations. We do it for cases when the subquery is coming from the MainFromClause, it doesn't contain any result operators and is projecting it's MainFromClause only in the selector. The optimization is the most prominent for queries with Include but will help other cases also.
Fixed in f022d66 |
Thanks! @maumar |
Steps to reproduce
Full example: EfCoreMultipleQueriesIssue.zip
IQueryable queryBug = db.Posts.OrderBy(x => x.Id).Include(x => x.PostTags).Where(x => x.PostTags.Any());
//Hundreds of
//SELECT[p].[PostId]
//FROM[PostTag] AS[p]
IQueryable queryBug2 = db.Posts.OrderBy(x => x.Id).Include(x => x.PostTags).Where(x => x.PostCategories.Any());
//Hundreds of
//SELECT[p].[PostId]
//FROM[PostTag] AS[p]
IQueryable queryOk = db.Posts.Where(x => x.PostTags.Any()).OrderBy(x => x.Id).Include(x => x.PostTags);
IQueryable queryOk2 = db.Posts.Include(x => x.PostTags).Where(x => x.PostTags.Any()).OrderBy(x => x.Id);
IQueryable queryOk3 = db.Posts.Include(x => x.PostTags).OrderBy(x => x.Id).Where(x => x.PostTags.Any());
The issue
Looks like part of the query is being evaluated locally, generating all those queries. It's not clear why.
The text was updated successfully, but these errors were encountered: