I have a query like this
return await _ctx.Activities
.Include(a => a.Attributes)
.Include(a => a.Roles)
.Include(a => a.Bookmarks)
.Include(a => a.VideoMetas)
.ThenInclude(vm => vm.Instances)
.Include(a => a.ImageMetas)
.ThenInclude(im => im.Instances)
.Include(a => a.Procedure)
.ThenInclude(p => p.Attributes)
.FirstOrDefaultAsync(a => a.Id == id);
Which turns out to be very slow. In EF 6
you can do .Include(v => v.VideoMetas.Select(vm => vm.Instances)
which is a bit faster (I guess, haven't looked at SQL Profiler and actual query tbh). How can I optimize that? I can also use EF Plus
where it has .IncludeOptimized()
but there is no version for .ThenInclude()
. I heard I can use .Select
instead of .Include()
but really not sure how I can handle that in this query.
AsNoTracking is used to increase performance, but returning entities instead of view models can affect performance far more.
IncludeOptimized allows you to optimize the query generated by EF by executing multiple smaller queries instead of executing only one monster SQL.
EF Core 6.0 performance is now 70% faster on the industry-standard TechEmpower Fortunes benchmark, compared to 5.0. This is the full-stack perf improvement, including improvements in the benchmark code, the . NET runtime, etc. EF Core 6.0 itself is 31% faster executing queries.
The EF Core 3.0 Currently does not support adding Filters in Include / ThenInclude methods. But this feature will available in the next version of EF Core. You can use the following operators
The EF Query Include Optimized feature lets you filter related entities that will be included. However, instead of to make one big query like Query Include Filter, the queries are split into several queries to optimize the performance like EF Core does.
For example, Customer contains a list of invoices and each invoice then contains a list of items. EF Core has a new extension method ThenInclude(). You can drill down thru relationships to include multiple levels of related data using the ThenInclude method.
The eager loading in EF Core done via the Include & ThenInclude methods. We need to supply the navigational property of the related entity as the argument. The next version of EF Core will also support the filtering & Ordering of the related data. You can apply on multiple tables and at multiple levels etc.
You'll want to split it into multiple queries, to speed up the performance. You can use explicit loading for this. It's not the prettiest solution, but it works. Hopefully an easier solution will come in EF 5.
I'm guessing a bit on which fields are collections and which are "normal" entries, but something like this:
var activity = await _ctx.Activities.FindAsync(Id);
await context.Entry(activity)
.Collection(a => a.Attributes)
.LoadAsync();
await context.Entry(activity)
.Collection(a => a.Roles)
.LoadAsync();
await context.Entry(activity)
.Collection(a => a.Bookmarks)
.LoadAsync();
await context.Entry(activity)
.Collection(a => a.VideoMetas)
.Query()
.Include(vm => vm.Instances)
.LoadAsync();
await context.Entry(activity)
.Collection(a => a.ImageMetas)
.Query()
.Include(im => im.Instances)
.LoadAsync();
await context.Entry(activity)
.Reference(a => a.Procedure)
.Query()
.Include(p => p.Attributes)
.LoadAsync();
return activity;
Update : As of EF Core 5 Microsoft have added .AsSplitQuery()
which allows doing this much less verbose with eager loading!
You can not. This is dimensional expansion SQL fights with. Ef 2.2 had what coudl be seen as an attempt to start with this, but they did not get it working and removed it.
Your best chance is to load in multiple (possibly parallel) queries and then stitch the results together in memory. For EF there are libraries to do that - not sure they exist for EfCore. They run the queries as multiple queries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With