从Entity Framework 4.1中的LINQ查询优化内存使用

时间:2011-10-14 01:52:01

标签: entity-framework-4.1 query-optimization

我目前有一个系统,用户可以注册并下注足球比赛的分数。 现在我有超过2万用户,超过300万投注。每周我都要生成一个排名,所以我有一个查询,在内存中加载所有用户的赌注就像这样:

from u in context.Set<User>().include("Bets").OrderByDescending(u => u.Points)
select u

其中积分是每次猜测所获得的积分之和。 在此查询结束后,我将用户及其位置保存在另一个表上以构建我的排名。

事实是,这个查询消耗了太多内存!超过4gb !!!我需要所有用户和赌注来计算排名。

我尝试的第一个选择是:创建另一个表来存储用户及其点。我会迭代这个查询,每次加载500个用户,而不是计算和保存,但我仍然坚持内存问题:

        int page = 0;
        int step = 500;
        while (page * step < count)
        {
            foreach (var u in context.Set<User>()
                                           .Skip(page * step)
                                           .Take(step).ToList())
            {
               //Saves in another table
            }
            page++;
        }
        //Sorts based on the data from this other table

由于这不起作用,我放弃了,然后我尝试做这样的事情:

var users = (from u in context.Set<User>().Include("Bets")
            select u).ToList();
context.Dispose()
var sortedUsers = from u in users.OrderByDescending(u => u.Points)
                  select u;

但也没解决......

我猜问题是关于保存所有跟踪信息的上下文。 有人有任何线索吗?如何使用EF 4.1处理大量数据?

由于


我注意到的另一件事。 假设我有用户A和用户B, 每个人只有1次投注到同一场比赛,我希望有类似的东西:

User A ---> Bet 
                \
                  Match
                /
User B ---> Bet 

但我有两个不同的Match实例具有相同的数据。 有没有办法避免这种情况?


为什么我不愿意将其放在存储过程中:

排名基于猜测,并且有关于此排序的一些规则。

用户有N个投注。每个赌注都与一个有分数的游戏相关联。

第一个分类标准是分数。所以我需要计算每次下注的积分(每个用户有大约200个投注,并且在锦标赛结束时将有大约300个投注)。那是第一次加入。

要计算每次下注的积分,我需要比赛的最终得分。那是另一个加入。

在得到每个赌注的点数之和(大约有10个条件)并按照它排序后,我仍然需要根据以下内容进行排序:

没有。正确的赌注, 获胜者被猜到的投注数量, 猜测一个分数的投注数, 最后一次下注的日期, 注册日期。

所以这是一个大约6个标准,大约3个连接和大量逻辑的巨大排序。在LINQ中计算这个非常简单,如果我必须将它放在SP上,则需要花费很多时间,而且更容易出错。 (从未在SP中尝试过TDD甚至单元测试......这个排名测试了一切)

2 个答案:

答案 0 :(得分:3)

我同意@Allan,理想情况下,这将在存储过程中完成。如果您可以发布计算的详细信息,也许其他人可以建议在存储过程中执行此操作的方法。

如果你想保持原样,你可以尝试一些事情:

  1. 使用AsNoTracking来避免缓存:context.Set<User>().AsNoTracking() // etc
  2. 如果您的UserBet类具有许多您不需要进行计算的属性,请将它们投影为只具有所需属性的匿名类型。
  3. 希望这会有所帮助,如果你尝试AsNoTracking,我会很想知道它有多大差异。

答案 1 :(得分:1)

Dude我认为如果你只是在存储过程中而不是在C#代码上计算这些数据会更明智。如果可以通过使用现有数据计算这些数据,则无需保存这些数据。将它们保存在另一个表中会导致数据冗余,并且会违反良好的数据库规范化规则。