简体   繁体   中英

EF Core Query Performance

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?

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.

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.

在此处输入图像描述

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM