为什么在带有 .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
) 将在 服务器端 执行,没有 不需要的提取 。
我真的希望我的标题有点正确,因为我正在努力用语言表达我的要求但是...
我目前正在努力掌握 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
) 将在 服务器端 执行,没有 不需要的提取 。