1

我的 SQL 和实体框架知识有些有限。在一个实体框架 (4) 应用程序中,我注意到完成我的一个方法调用需要很长时间(大约 2 分钟)。第一个查询不需要太多时间,但是当我遍历查询返回的实体框架对象时,即使我只是读取(而不是修改)我应该得到的数据,完成嵌套循环也需要很长时间,即使每个列表中只有几十个条目和几级循环。

我希望下面的示例可以用更高级的查询重新编写,该查询可能包括我在循环中使用一些我真的不知道如何使用的 SQL 词进行的所有过滤,所以如果有人可以告诉我什么等效的 SQL 表达式将是,这对我来说非常有教育意义,并且可能解决我当前的性能问题。

此外,由于此应用程序的其他部分和我开发的其他应用程序经常想要对 SQL 数据进行更复杂的计算,我还想知道一种将数据从 Entity Framework 检索到本地内存对象的好方法,这些对象在读取时不会有很大的延迟他们。在我的 LINQ-to-SQL 项目中存在类似的性能问题,我通过重构整个应用程序以将所有 SQL 数据加载到 RAM 中的并行对象中解决了这个问题,我必须自己编写,我想知道是否没有一种更好的方法来告诉 Entity Framework 不要继续执行它正在执行的任何高延迟通信,或者加载到本地 RAM 对象中。

在下面的示例中,代码通过 SQL 查询获取某个成员(即人)在某个日期的食物菜单项列表,然后我使用其他查询和循环根据两个条件过滤掉菜单项: 1 ) 如果该成员对配方所属的任何组 id 的评分为零(多对多关系),并且 2) 如果该成员对配方本身的评分为零。

例子:

List<PFW_Member_MenuItem> MemberMenuForCookDate =
            (from item in _myPfwEntities.PFW_Member_MenuItem
             where item.MemberID == forMemberId
             where item.CookDate == onCookDate
             select item).ToList();

        // Now filter out recipes in recipe groups rated zero by the member:
        List<PFW_Member_Rating_RecipeGroup> ExcludedGroups =
            (from grpRating in _myPfwEntities.PFW_Member_Rating_RecipeGroup
             where grpRating.MemberID == forMemberId
             where grpRating.Rating == 0
             select grpRating).ToList();
        foreach (PFW_Member_Rating_RecipeGroup grpToExclude in ExcludedGroups)
        {
            List<PFW_Member_MenuItem> rcpsToRemove = new List<PFW_Member_MenuItem>();
            foreach (PFW_Member_MenuItem rcpOnMenu in MemberMenuForCookDate)
            {
                PFW_Recipe rcp = GetRecipeById(rcpOnMenu.RecipeID);
                foreach (PFW_RecipeGroup group in rcp.PFW_RecipeGroup)
                {
                    if (group.RecipeGroupID == grpToExclude.RecipeGroupID)
                    {
                        rcpsToRemove.Add(rcpOnMenu);
                        break;
                    }
                }
            }
            foreach (PFW_Member_MenuItem rcpToRemove in rcpsToRemove)
                MemberMenuForCookDate.Remove(rcpToRemove);
        }
        // Now filter out recipes rated zero by the member:
        List<PFW_Member_Rating_Recipe> ExcludedRecipes =
            (from rcpRating in _myPfwEntities.PFW_Member_Rating_Recipe
             where rcpRating.MemberID == forMemberId
             where rcpRating.Rating == 0
             select rcpRating).ToList();
        foreach (PFW_Member_Rating_Recipe rcpToExclude in ExcludedRecipes)
        {
            List<PFW_Member_MenuItem> rcpsToRemove = new List<PFW_Member_MenuItem>();
            foreach (PFW_Member_MenuItem rcpOnMenu in MemberMenuForCookDate)
            {
                if (rcpOnMenu.RecipeID == rcpToExclude.RecipeID)
                    rcpsToRemove.Add(rcpOnMenu);
            }
            foreach (PFW_Member_MenuItem rcpToRemove in rcpsToRemove)
                MemberMenuForCookDate.Remove(rcpToRemove);
        }
4

2 回答 2

2

您可以使用 EFProf http://www.hibernatingrhinos.com/products/EFProf来跟踪查看 EF 发送到 SQL 的确切内容。它还可以显示您发送了多少查询以及有多少独特查询。它还为您提供了对每个查询的一些分析(例如,它是否未绑定等)。具有导航属性的实体框架,很容易没有意识到您正在发出数据库请求。当您处于循环中并具有导航属性时,您会遇到 N + 1 问题。

于 2013-03-13T22:37:27.960 回答
1

如果您首先使用代码来启用代理,则可以在模型的 List 部分使用关键字 Virtual,这样您就不必一次取回所有数据,只需在需要时即可。

还考虑对只读数据使用 NoTracking

context.bigTable.MergeOption = MergeOption.NoTracking; 
于 2013-03-13T22:18:34.980 回答