EF核心查询性能

时间:2020-06-13 08:27:22

标签: entity-framework ef-core-3.1

我有一个查询,加载速度非常慢。我认为这是很不对劲,但是我不明白为什么。 在我的应用程序中,我有一个实体KeyText:

{{ }}

大多数其他实体都具有多个这些键文本。它只是填充组合框的一种简单方法。 因此,如果我这样通过ef内核加载:(那么ThenInclude lambda中的所有内容都是KeyText)

public class KeyText
    int Id
    Group Group
    string Text

在实际应用中,它最多可以加载20秒,这非常荒谬 数据量。我说的像是5个收藏集中的5个条目。

但是,如果我这样加载:

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);

它立即加载。为什么是这样?第一个查询错了吗?

2 个答案:

答案 0 :(得分:0)

假设您有5家公司,每家公司有5个地址:

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);

此代码生成Sql的5 * 5 = 25个左联接,每个联接由3个联接(公司*地址*类型)组成


var companies = context.Companies;
companies.adresses = context.Adresses
    .Include(a => a.AdressType)
    .Include(a => a.CityType)
    .Include(a => a.AnotherKeyText)
    .Include(a => a.DifferentKeyText);

此代码代表Sql生成5个左联接,每个联接由2个联接(地址*类型)组成

因此,很明显,第一种方法会严重损害您的性能。

无论如何,请尽量不使用Include。而是使用JoinSelect表达式加载所需的最小数据量。

答案 1 :(得分:0)

另一个在 EF 中加快查询速度的选项是使用.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);

在只读方案中使用结果时,没有跟踪查询很有用。由于不需要设置更改跟踪信息,因此执行起来更快。如果您不需要更新从数据库中检索到的实体,则应使用无跟踪查询。您可以将单个查询交换为无跟踪

默认情况下,返回实体类型的查询正在跟踪。这意味着您可以对这些实体实例进行更改,并使这些更改由SaveChanges()保留。

默认情况下,当您从数据库加载数据时,ChangeTracker已跟踪所有记录,这将导致速度和内存分配略有下降。

enter image description here