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

时间:2015-02-24 15:57:14

标签: c# performance linq entity-framework

我有一个linq查询需要几秒钟(~2.6秒)才能运行。但我希望尽可能少地减少它。

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

我还测试了没有include语句的查询,但是我的操作在get请求之后进一步减慢了速度,所以我离开了包含来优化我的其他操作。

主要目标是减少数据库通话,因此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。

一个大的表现小偷是关联市场(我不知道为什么,EF不喜欢的东西。)

这将查询缩小到大约0.4秒的平均值。 整个操作设置从4秒到惊人的0.7秒。

1 个答案:

答案 0 :(得分:2)

您执行的每个包含都将最终在数据库中执行连接。 假设您的左表是非常大的1024字节的记录大小,并且您有许多细节,比如1000,并且详细记录大小只有100。 这将导致左表的信息重复1000次,这些信息将由db放在线上,EF必须过滤掉重复的内容以创建左实例。

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

我有一个使用以下原理的例子。它可以比依赖包含快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来尝试避免第二个查询,重点是在这种情况下2个查询比单个查询更快。

最重要的是要考虑的不仅仅是避免延迟加载,还需要考虑哪些包含需要而哪些不需要。您可能需要该信息,并且包含快速简便,但在同一上下文中的额外查询可以更快。