代码之家  ›  专栏  ›  技术社区  ›  Gleno

使用foreach遍历IQueryable会导致内存不足异常

  •  11
  • Gleno  · 技术社区  · 15 年前

    我使用foreach/IQueryable和linqtosql遍历一个较小的(~10GB)表。 看起来像这样:

    using (var conn = new DbEntities() { CommandTimeout = 600*100})
    {
         var dtable = conn.DailyResults.Where(dr => dr.DailyTransactionTypeID == 1);
         foreach (var dailyResult in dtable)
         {
            //Math here, results stored in-memory, but this table is very small. 
            //At the very least compared to stuff I already have in memory. :)
         }
    }
    

    visualstudio调试器在foreach循环的基础上运行一段时间后抛出内存不足异常。我假设dtable的行没有被刷新。怎么办?

    5 回复  |  直到 12 年前
        1
  •  19
  •   themefield Zain Ali    5 年前

    这个 IQueryable<DailyResult> dtable 将尝试在枚举时将整个查询结果加载到内存中。。。在foreach循环的任何迭代之前。在foreach循环的迭代过程中,它不会加载一行。如果你想要这种行为,就用 DataReader .

        2
  •  7
  •   Sherlock    15 年前

    conn.DailyResults.Where(dr => dr.DailyTransactionTypeID == 1).Skip(x).Take(y);
    
        3
  •  2
  •   dckuehn sasha_gud    9 年前

    int iTake = 40000;
    int iSkip = 0;
    int iLoop;
    ent.CommandTimeout = 6000;
    while (true)
    {
      iLoop = 0;
      IQueryable<viewClaimsBInfo> iInfo = (from q in ent.viewClaimsBInfo
                                           where q.WorkDate >= dtStart &&
                                             q.WorkDate <= dtEnd
                                           orderby q.WorkDate
                                           select q)
                                          .Skip(iSkip).Take(iTake);
      foreach (viewClaimsBInfo qInfo in iInfo)
      {
        iLoop++;
        if (lstClerk.Contains(qInfo.Clerk.Substring(0, 3)))
        {
              /// Various processing....
        }
      }
      if (iLoop < iTake)
        break;
      iSkip += iTake;
    }
    

    您可以看到,我必须检查是否已用完记录,因为foreach循环将以40000个记录结束。不好的。

    2011年6月10日更新:即使这样也不行。在2000000条左右的记录中,我得到了一个内存不足的异常。它也极其缓慢。当我将它修改为使用OleDB时,它运行了大约15秒(而不是10分钟以上),并且没有耗尽内存。有没有人有一个LINQ解决方案可以快速工作和运行?

        4
  •  0
  •   Seann Alexander    13 年前

        5
  •  0
  •   parfilko    8 年前

    .AsNoTracking() -它告诉我们 不缓存

    using (var conn = new DbEntities() { CommandTimeout = 600*100})
    {
         var dtable = conn.DailyResults
                    .AsNoTracking()      // <<<<<<<<<<<<<<
                    .Where(dr => dr.DailyTransactionTypeID == 1);
         foreach (var dailyResult in dtable)
         {
            //Math here, results stored in-memory, but this table is very small. 
            //At the very least compared to stuff I already have in memory. :)
         }
    }