在LINQ查询上缓慢的foreach() – ToList()极大地提升了性能 – 为什么会这样?

我有点把握整个延迟执行的概念,但以下让我感到困惑……

在包含大约1000行的DataTable上,我调用了AsEnumerable() 。 然后我选择返回到强类型类的IEnumerable中的实体(1) ……这就是我感到困惑的地方:我在集合上做了一个foreach循环; 使用一堆Where()调用(2)从集合中的各个项目中选择东西……而且它已经慢了。

  1. DataTable.AsEnumerable().Select(r => new ObjectRepresentation { ... });
  2. item.Where(i => i.SomeEnum == SomeEnum.Something)

…但是如果我在DataTable上调用AsEnumerable()之后立即调用ToList() ,则foreach循环只需不到一秒钟即可完成。

我在这里想念的是什么? 每次我的循环迭代时,我是否有效地调用AsEnumerable() ? 或者每次我访问集合中的项目? 或者每次我对集合中的项目进行Where()调用? 或者以上所有?

更新

一些完整的代码:

 public class ObjectRepresentation { public SomeEnum SomeEnum { get; set; } } var collection = DataTable.AsEnumerable().Select(r => new ObjectRepresentation { SomeEnum = (SomeEnum)Convert.ToInt32(r["SomeEnum"]) }); foreach(var item in collection) // slow loop { // 10 or so Where() calls on item inside this loop } collection = collection.ToList(); // Hit hyper speed button! foreach(var item in collection) // fast loop { // 10 or so Where() calls on item inside this loop } 

在您键入之前,它不会从数据库中获取所有项目

  ToList or First or Single 

在foreach中,您将为每个项目向数据库发送查询。 所以它工作得更慢。 打开你的sql profiler以更好地理解。

您不了解哪些方法被延迟,哪些方法不延迟,因此您无法理解代码何时定义操作与执行操作。

这些都是推迟的。 它们定义但不执行操作。

 source.AsEnumerable source.Select source.Where 

这些列举了源,因此不会延迟。

 source.ToList source.First source.Single foreach(var x in source) 

实际上,您似乎并不清楚什么是代码的执行以及在实际使用结果后(可能)稍后执行的意图的定义是什么。 我建议阅读LINQ的这一部分。

并且可能尝试使用附加的调试器执行两个变体,这样您就可以实际查看正在执行的代码以及数据实际发生的情况。 你可能会在这里遇到一个(大?)惊喜……