为什么在带有 .Where().Select() 过滤器的 IEnumerable<Entity> 上调用 .ToList() 比在实体本身上调用它慢?

Why calling .ToList() on an IEnumerable<Entity> with .Where().Select() filters slower than calling it on the Entity itself?

我真的希望我的标题有点正确,因为我正在努力用语言表达我的要求但是...

我目前正在努力掌握 IEnumerables。

我的应用程序中有一个 class,如下所示:

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()从RDBMS获取所有记录(比如,所有1_000_000)到工作站,然后过滤它们(Where), 订购它们 (OrderBy) 等

恰恰相反

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

IQueryable<T> 直到最后 (.ToList()) 这意味着 SQL 查询已创建 和所有过滤 (Where),排序 (OrderBy) 将在 服务器端 执行,没有 不需要的提取