Reputation: 44
I have a query that loads extremely slowly. I think something is very wrong with it, but i dont understand why. In my application i have an entity KeyText:
public class KeyText
int Id
Group Group
string Text
Most other entities have several of these keytexts. Its just a simple way of filling comboboxes. So if i load via ef core like this: (Everything in the ThenInclude lambda is a KeyText)
context.Companies
.Include(c => c.Adresses).ThenInclude(a => a.AdressType);
.Include(c => c.Adresses).ThenInclude(a => a.CityType);
.Include(c => c.Adresses).ThenInclude(a => a.AnotherKeyText);
.Include(c => c.Adresses).ThenInclude(a => a.DifferentKeyText);
This can, in the real app, load up to 20 seconds for a ridicolously low amount of data. I'm talking like 5 entries in 5 collections.
However if i load like this:
var companies = context.Companies;
companies.adresses = context.Adresses
Include(a => a.AdressType)
Include(a => a.CityType)
Include(a => a.AnotherKeyText)
Include(a => a.DifferentKeyText);
It loads instantly. Why is this? Is the first query that wrong?
Upvotes: 1
Views: 278
Reputation: 5861
Another option to speed up your query in EF is using .AsNoTracking()
var companies = context.Companies.AsNoTracking();
companies.adresses = context.Adresses.AsNoTracking()
.Include(a => a.AdressType)
.Include(a => a.CityType)
.Include(a => a.AnotherKeyText)
.Include(a => a.DifferentKeyText)
context.Companies.AsNoTracking()
.Include(c => c.Adresses).ThenInclude(a => a.AdressType);
.Include(c => c.Adresses).ThenInclude(a => a.CityType);
.Include(c => c.Adresses).ThenInclude(a => a.AnotherKeyText);
.Include(c => c.Adresses).ThenInclude(a => a.DifferentKeyText);
No tracking queries are useful when the results are used in a read-only scenario. They're quicker to execute because there's no need to set up the change tracking information. If you don't need to update the entities retrieved from the database, then a no-tracking query should be used. You can swap an individual query to be no-tracking
By default, queries that return entity types are tracking. Which means you can make changes to those entity instances and have those changes persisted by SaveChanges()
.
When you load data from Database by default all records has been tracked by ChangeTracker
and this will cause a slight drop in speed and memory allocation.
Upvotes: 0
Reputation: 4461
Let assume you have 5 companies, each one has 5 Addresses:
context.Companies
.Include(c => c.Adresses).ThenInclude(a => a.AdressType);
.Include(c => c.Adresses).ThenInclude(a => a.CityType);
.Include(c => c.Adresses).ThenInclude(a => a.AnotherKeyText);
.Include(c => c.Adresses).ThenInclude(a => a.DifferentKeyText);
This code generates 5*5=25 left join behalf of Sql each one composed of 3 join (Companies * Adresses * types)
var companies = context.Companies;
companies.adresses = context.Adresses
.Include(a => a.AdressType)
.Include(a => a.CityType)
.Include(a => a.AnotherKeyText)
.Include(a => a.DifferentKeyText);
This code generates 5 left join behalf of Sql each one composed of 2 join (Adresses * types)
So it's obvious that first approach damages your performance significantly.
Anyway try to not use Include
as far as you can. Instead load minimum amount of data that you need and with Join
and Select
expressions.
Upvotes: 1