IQueryable.Where.ToList VS IQueryable.ToList.Where,哪个查询在性能方面



我有两个查询,两个查询都产生相同的结果,但我想知道哪个更有效。下面是查询,我只写了查询子句。两个查询的内部条件相同。

  1. IQueryable((。其中((。ToList((;
  2. IQueryable((。ToList((。其中((;

最后,我尝试了下面的代码,它显示"IQueryable((。ToList((。Where((;" 更好。有几个问题我不明白:1.没有看到我下面的临时代码,哪个查询更有效?2. 据我所知,IQueryable 非常适合查询远程数据。那么,先过滤掉项目,然后使用ToList,这样我们就不需要对不相关的项目执行ToList功能,难道不是更好吗?(如果是这种情况,那么为什么下面的代码说查询 2 更有效?

Stopwatch st1 = new Stopwatch();
Stopwatch st2 = new Stopwatch();
int counter = 10000;
IEnumerable<Employee> iEmp = null;
IQueryable<Employee> qEmp = null;
BindingList<Employee> bList = new BindingList<Employee>();
for (int i = 1; i <= counter; ++i)
{
    bList.Add(new Employee
    {
        Department = $"Dept - {i}",
        EmployeeID = i,
        EmployeeName = $"Employee - {i}",
        Salary = i + 10000
    });
}
iEmp = bList.AsEnumerable<Employee>();
qEmp = bList.AsQueryable<Employee>();
st1.Start();
var t = qEmp.Where(x => x.EmployeeID % 2 == 0).ToList();
st1.Stop();
Console.WriteLine($"Queryable-Where-ToList: {st1.ElapsedTicks}");
st2.Start();
var t1 = qEmp.ToList().Where(x => x.EmployeeID % 2 == 0);
st2.Stop();
Console.WriteLine($"Queryable-ToList-Where: {st2.ElapsedTicks}");
Console.ReadKey();

你应该使用 IQueryable.Where.ToList .这样,筛选将在查询上下文中进行,而不是像IQueryable.ToList.Where那样先收集结果并在内存中筛选所有结果。

在您的示例中,BindingList ,这并不重要,但在使用实体框架之类的东西时确实很重要。

在EF的情况下,给定

Id | Name
1  | Daniel
2  | Miranda
3  | Elianna

执行.ToList将首先返回所有 3 条记录。然后,执行Where即可处理内存中的这些对象。

 var list = query.ToList();
 list.Count == 3; // true
 list.Where(i => i.Id % 2 == 0); // Returns only Miranda

但是,首先使用.Where,它会将其转换为SQL(此处为伪SQL(,然后收集结果。

SELECT * FROM Table WHERE Id % 2 = 0

在 C# 中:

 var list = query.Where(i => i.Id % 2 == 0).ToList();
 list.Count == 1; // true, only Miranda

在为什么 2 更快的情况下,您的测试是有缺陷的。这些测试不是单独运行的。它们在短时间内对相同的数据进行操作,这可能会导致 CPU/运行时/操作系统为您优化一些内容。

调用ToList时,您将把所有项目都放入内存中。当您使用 Where -语句过滤此结果时,所有这些过滤都将在客户端(可以这么说(上进行,在您的情况下,这是在内存中。但是,当您在调用ToList之前将第一种方法与 Where 语句一起使用时,过滤发生在数据库端,因此应该快得多。

目前尚不清楚为什么反之亦然的方法会更快,但从我的角度来看,您应该尽可能长时间地使用该IQueryable,并在完成查询后将结果放入内存中(这实际上使其成为IEnumerable(。

在你的例子中,用你的测试代码IQueryable((。ToList((。Where(( 工作得更快,因为实现了 AsQueryable、ToList 和 Where。AsQueryable 只是包装 BindingList,它是 ICollection,ToList 使用 ICollection 比使用 Where 返回的 IEnumerable 更快。

在一般情况下,IQueryable 应该用于构建对数据存储的查询,因此在数据库端执行整个查询应该更有效(极少数情况除外(。

最新更新