LINQ是否懒惰评估?

时间:2011-02-04 12:46:36

标签: linq-to-sql

问候,我有以下问题。我没有找到它的确切答案,这对我来说真的很有趣。假设我有以下代码从数据库中检索记录(例如,为了将其导出到XML文件)。

var result = from emps in dc.Employees
  where emps.age > 21
  select emps;

foreach (var emp in result) {
  // Append this record in suitable format to the end of XML file
}

假设有一百万条记录满足代码中的 where 条件。会发生什么?所有这些数据将在到达 foreach 构造时立即从SQL Server检索到运行时内存,或者在必要时检索它,第一个记录,第二个。换句话说,LINQ是否真的通过迭代大型集合来处理这种情况(详情请参阅我的post)?

如果没有,那么如何克服内存问题呢?如果我真的需要遍历大集合,我该怎么办?借助Count函数计算集合中元素的实际数量,然后按小部分从数据库中读取数据。有没有一种简单的方法来实现LINQ框架的分页?

4 个答案:

答案 0 :(得分:10)

将一次从SQL Server检索所有数据,并将其放入内存。我能想到的唯一解决方法是以较小的块处理数据(如使用Skip()和Take()的页面。但是,当然,这需要更多的SQL Server命中。

这是我写的Linq分页扩展方法:

public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize)
    {
        return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
    }

答案 1 :(得分:5)

是的,LINQ使用延迟评估。当foreach开始执行时,将查询数据库,但它会一次性获取所有数据(一次只能为一个结果执行数百万次查询效率低得多)。

如果您担心一次性引入太多结果,您可以使用Skip和Top一次只获得有限数量的结果(从而对结果进行分页)。

答案 2 :(得分:1)

当您调用ToList或类似方法时,它将被检索。 LINQ延迟执行:

方法 - 即使延迟执行并在OR / M或任何其他LINQ提供程序的情况下从数据源加载整个集合 - 将由LINQ对象源的实现者确定。

例如,某些OR / M可能会提供延迟加载,这意味着您的“整个客户列表”将类似于游标,并访问其中一个项目(一个员工),还有一个属性,将仅加载员工本身或被访问的财产。

但是,无论如何,这些都是基础。

编辑:现在我看到它是一个LINQ-to-SQL的东西...或者我不知道问题的作者是否误解了LINQ并且他不知道LINQ不是LINQ-to-SQL,但它更像是模式和语言特征。

答案 3 :(得分:0)

好的,现在感谢answer我有一个想法 - 如何将页面功能与收益率回报的可能性混合起来?以下是代码示例:

// This is the original function that takes the page
public static IEnumerable<TSource> Page<TSource>(this IEnumerable<TSource> source, int pageNumber, int pageSize) {
  return source.Skip((pageNumber - 1) * pageSize).Take(pageSize);
}

// And here is the function with yield implementation
public static IEnumerable<TSource> Lazy<TSource>(this IEnumerable<TSource> source, int pageSize) {
  int pageNumber = 1;
  int count = 0;

  do {
    IEnumerable<TSource> coll = Page(source, pageNumber, pageSize);
    count = coll.Count();
    pageNumber++;
    yield return coll;
  } while (count > 0);
}


// And here goes our code for traversing collection with paging and foreach
var result = from emps in dc.Employees
  where emps.age > 21
  select emps;

// Let's use the 1000 page size
foreach (var emp in Lazy(result, 1000)) {
  // Append this record in suitable format to the end of XML file
}

我认为这样我们可以克服内存问题,但是 foreach 的结构不会那么复杂。