优化实体框架查询,避免延迟加载



我有一个linq查询,它需要几秒钟(~2.6s)才能运行。但我想尽量减少。

我只需要阅读,所以我已经包含了.AsNoTracking()行为。

我还测试了不带include语句的查询,但在get请求后我的操作进一步减慢了速度,所以我留下include来优化我的其他操作。

主要目标是减少数据库对话,因此使用ToList()、Include语句

代码:

var obj = _context.MyContextModel.AsNoTracking()
            .Where(x => x.CategoryList.Model.Id == 1)
            .Where(x => x.CategoryList.Model.TypeId == 1)
            .Where(x => x.Year.Select(y=>y.Datetime).Any(item => item.Year == 2010))
            .Include(x => x.LinkedMarket).AsNoTracking()
            .Include(x => x.Year).AsNoTracking()
            .Include(x => x.CategoryList).AsNoTracking()
            .Include(x => x.CategoryList.Model).AsNoTracking();
return obj.AsParallel().ToList();

此操作通常返回1000-2000条MyContextModel记录,不包括"includes"

如何进一步优化?我应该将对象加载到容器类中吗?还是其他解决方案?

更新

_context.Configuration.ProxyCreationEnabled = false;
_context.Configuration.LazyLoadingEnabled = false;
var obj = _context.MyContextModel.AsNoTracking()
                .Where(x => x.CategoryList.Model.Id == 1)
                .Where(x => x.CategoryList.Model.TypeId == 1)
                .Where(x => x.LinkedMarket.FirstOrDefault(mar=>mar.MarketID == marketId) != null)
                .Include(x => x.Year).AsNoTracking()
                .Include(x => x.CategoryList).AsNoTracking()
                .Include(x => x.CategoryList.Model).AsNoTracking();
return obj.AsParallel().ToList();

基本上,我已经删除了过滤年份的where子句(我稍后会这样做,因此包括年份)我添加了一个Where子句,从getgo开始指定市场。

我已经删除了包含市场的Include。

一个业绩大盗是关联市场(我不知道为什么,英孚不喜欢。)

这将查询减少到平均0.4秒左右。整个操作从4秒多设置为惊人的0.7秒。

您所做的每一次include最终都会在数据库中执行一个联接。假设您的左表的记录大小非常大,为1024字节,并且您有许多详细信息,比如1000,并且详细记录大小只有100。这将导致左表的信息被重复1000次,这些信息将由db放到线上,EF必须过滤掉重复的信息才能创建左实例。

最好不要使用include并执行显式加载。基本上在同一上下文上执行2个查询。

下面我有一个使用这个原理的例子。它可以比依赖include快10倍。(数据库只能有效地处理有限数量的联接)

var adressen = adresRepository
                .Query(r => r.RelatieId == relatieId)
                .Include(i => i.AdresType)
                .Select().ToList();
var adresids = (from a in adressen select a.AdresId).ToList();
            IRepositoryAsync<Comm> commRepository = unitOfWork.RepositoryAsync<Comm>();
            var comms = commRepository
                .Query(c => adresids.Contains(c.AdresId))
                .Include(i => i.CommType)
                .Select();

对于commType和adresType,我使用include,因为存在1对1的关系,我避免了太多的联接,因此我的多个查询将比使用include的单个查询更快。我没有在第一个查询中包括Comms,以避免第二个查询,重点是在这种情况下,两个查询比一个查询更快。

底线是,除了避免懒惰负载之外,还需要考虑哪些包含是需要的,哪些不需要。您可能需要这些信息,include既快捷又简单,但在同一上下文中进行额外查询可能会更快。

最新更新