Performance LINQ内存不足错误

Performance LINQ内存不足错误,performance,linq,entity-framework,system.reactive,Performance,Linq,Entity Framework,System.reactive,我正在查询200000条记录,并耗尽了服务器的所有内存(毫不奇怪)。我是LINQ的新手,因此我发现以下代码应该对我有所帮助,但我不知道如何使用它: public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize) { List<T> nextbatch = new List<T>(batc

我正在查询200000条记录,并耗尽了服务器的所有内存(毫不奇怪)。我是LINQ的新手,因此我发现以下代码应该对我有所帮助,但我不知道如何使用它:

public static IEnumerable<IEnumerable<T>> Batch<T>(this IEnumerable<T> collection, int batchSize)
{
    List<T> nextbatch = new List<T>(batchSize);
    foreach (T item in collection)
    {
        nextbatch.Add(item);
        if (nextbatch.Count == batchSize)
        {
            yield return nextbatch;
            nextbatch = new List<T>(batchSize);
        }
    }
    if (nextbatch.Count > 0)
        yield return nextbatch;
}

我会使用Linq的Skip和Take来获取批次

看看这个:


它是一个扩展方法,因此如果它是静态类的一部分,并且代码中有对该类命名空间的引用,则可以执行以下操作:

var crmMetricsBatches = _crmDbContext.tpm_metricsSet
                        .Where(a => a.ModifiedOn >= lastRunDate)
                        .AsEnumerable() // !!
                        .Batch(20);
除非这没用。通过
.AsEnumerable()
,您仍然可以获取内存中的所有数据,但现在是20个数据块。这是因为您不能直接针对
IQueryable
:实体框架将尝试将其转换为SQL,但当然不知道如何执行

正如TGH所说,
Skip
Take
更适合于此:

var crmMetricsPage = _crmDbContext.tpm_metricsSet
                        .Where(a => a.ModifiedOn >= lastRunDate)
                        .OrderBy(a => a.??) // some property you choose
                        .Skip(pageNo * pageSize)
                        .Take(pageSize);
其中
pageNo
0
计数到您需要的页数(
-1
Skip
Take
是表达式,EF知道如何将它们转换为SQL。EF需要
OrderBy
,才能知道从何处开始跳过

在这个称为分页的过程中,您总是一次获得
pageSize
记录。查询的数量更多,但节省了资源。一个条件是您可以提前确定
页面大小。我不知道这是否符合你的逻辑


如果无法使用分页,则应尝试缩小筛选器(
其中(a=>a.ModifiedOn>=lastRunDate
),例如,尝试在一天或一周内分批获取数据。

是否需要在循环中保存更改?好的观点。我可以在保存之前添加200k对象吗?Linq对我来说是新的。200k听起来似乎很多,但这取决于对象,当然也取决于您的服务器。给定4GB内存和10KB大小的对象…谢谢。此方法修复了问题内存问题,但它已经运行了12个小时,只有45000条记录。有没有加快速度的想法?什么?页面大小是多少?您和
ModifiedOn
的排序列上是否有索引?以及哪个数据库(+version)你使用过吗?我将页面大小从5000更改为500,这大大加快了过程。现在我注意到,你还应该分批保存,并为每个批使用新的上下文。哇……快多了!我理解分批保存的好处,但新的上下文有何帮助?
var crmMetricsPage = _crmDbContext.tpm_metricsSet
                        .Where(a => a.ModifiedOn >= lastRunDate)
                        .OrderBy(a => a.??) // some property you choose
                        .Skip(pageNo * pageSize)
                        .Take(pageSize);