奇怪的EF行为 - 意外的长时间

时间:2012-11-26 14:33:39

标签: c# database performance entity-framework

我首先拥有EF,数据库。我有三个模型类:ABC。 模型AB的m2m关系,BC的m2m关系。

我列出了A的相关BC的子集。

在测试环境中,子集中有大约20个模型A,只有少数具有任何相关B,如果有,则在大多数情况下只有一个。

模型B始终只有一个相关的C。我不想更改它,因为将来会有更多与C相关的B

我的第一个方法是:

var listA = new Entities(...).As.Where(...).ToList();
foreach (var objA in listA){
    var listC = objA.Bs.ToList().Select(b => b.FirstOrDefault(c => ...)).ToList();
}

花了大约164毫秒 - 很长时间。

所以我想要优化它。

如您所见,第一行IQueryable<A>更改为List<A>。 在这一刻,我认为,查询已经执行。

当我想Bs获取AC获得B时,我认为会执行另一个查询。

然后我搜索并找到Include方法。在第二个approuch我使用它像:

var listA = new Entities(...).As.Include("Bs.Cs").Where(...).ToList();
foreach (var objA in listA){
    var listC = objA.Bs.ToList().Select(b => b.FirstOrDefault(c => ...)).ToList();
}

在我看来,执行应该需要大约10毫秒,但现在需要550毫秒。

当我只列出与AsBs相关的Cs时,它需要大约10毫秒。

我做错了什么?

编辑:对不起,C有FK到B.但我认为它没有改变任何东西。

2 个答案:

答案 0 :(得分:0)

如果您的DbContext支持延迟加载“默认情况下为true”,只要您调用objA.Bs.ToList()b => b.FirstOrDefault(c => ...) ,就会产生很多针对数据库的命中,因为您没有包含这些导航属性在您的第一个listA查询中

无论如何都要尝试使用Include方法

var listA = new Entities(...).As.Include("Bs").Include("Bs.Cs").Where(...).ToList();

答案 1 :(得分:0)

根据我的经验,显式加载相关对象的速度要快一些。请尝试使用对象Load()方法加载并使用IsLoaded检查它是否已加载。另外,关闭延迟加载并明确打开连接可能有所帮助。

以下内容可能有所帮助。

var listA = from o in context where (...) select o;
foreach (var i in listA)
            {
                if (!i.Bs.IsLoaded)
                    i.Bs.Load();
                if (i.Bs != null)
                {
                    if (!i.Bs.Cs.IsLoaded)
                        i.Bs.Cs.Load();
                }

            }