为什么要打电话.ToList() 在 IEnumerable<Entity> with .其中()。select() 过滤器比在实体本身上调用它慢?



我真的希望我的标题有点正确,因为我很难用语言表达我的要求,但。。。

我目前正在努力掌握IEnumerables。

我的应用程序中有这样一个类:

public class MyDataRepo : IDisposable
{
private MyEntities context;
public MyDataRepo()
{ context = new MyEntities(); }
public IEnumerable<MyItem> GetMyItems()
{ return context.MyItems.AsEnumerable(); }
public void Dispose()
{ context.Dispose(); }
}

我想我可以这样使用它:

using (MyDataRepo repo = new MyDataRepo())
{ 
List<int> MyItemIDs = repo.GetMyItems().Where(x => x.ItemName == "Item Name")
.OrderBy(x => x.ItemMajorIssueNumber)
.ThenBy(x => x.ItemMinorIssueNumber)
.Select(x => x.ItemID).ToList();
}

但它比仅仅这样做要慢得多:

using (MyEntities context = new MyEntities())
{
List<int> MyItemIDs = context.MyItems.Where(x => x.ItemName == "Item Name")
.OrderBy(x => x.ItemMajorIssueNumber)
.ThenBy(x => x.ItemMinorIssueNumber)
.Select(x => x.ItemID).ToList();
}

我只是想知道为什么?

根据我的理解,IEnumerable在调用.ToList()之前不会对数据库执行任何操作。

在我看来,它们应该是相同的查询,但第二个查询几乎是即时的,因为第一个查询大约需要4-6秒。

我很感激我可能完全误解了IEnumerable,尽管它很常见。

理想情况下,我宁愿只调用IEnumerable<>并对其应用过滤器,然后调用.ToList()来获得我想要的结果,也不必为我需要的针对MyItems的所有查询编写几个方法。

这里我们有IEnumerable<T>IQueryable<T>行为的区别。当你把

List<int> MyItemIDs = repo
.GetMyItems()
.Where(x => x.ItemName == "Item Name")
...

实际上是

List<int> MyItemIDs = context
.MyItems
.AsEnumerable() <- This is the felony!
.Where(x => x.ItemName == "Item Name")
...

通过.AsEnumerable()将所有记录(例如,所有1_000_000记录(从RDBMS提取到工作站,然后对其进行筛选(Where(、排序(OrderBy(等。

相反,

List<int> MyItemIDs = context
.MyItems
.Where(x => x.ItemName == "Item Name")
...

IQueryable<T>直到最后(.ToList()(,这意味着创建的SQL查询和所有筛选(Where(、排序(OrderBy(将在服务器端上执行,而不会出现不需要的提取

最新更新