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

时间:2017-03-17 14:54:23

标签: c# performance linq iqueryable

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

  1. 的IQueryable()其中()ToList()。;
  2. 的IQueryable()ToList()其中();
  3. 在我结束时,我尝试了下面的代码并显示“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();
    

3 个答案:

答案 0 :(得分:4)

您应该使用IQueryable.Where.ToList。这样,过滤将在查询的上下文中进行,而不是首先收集结果并将所有结果过滤到内存中,如IQueryable.ToList.Where那样。

在使用BindingList的示例中,这并不重要,但 在使用Entity Framework之类的内容时非常重要。

在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 /运行时/操作系统为您优化一些内容。

答案 1 :(得分:1)

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

目前尚不清楚为什么反之亦然会更快,但从我的观点来看,你应尽可能使用IQueryable并将结果记录到内存中(有效地使其成为IEnumerable )当你完成查询时。

答案 2 :(得分:1)

在您的情况下,使用您的测试代码IQueryable()。ToList()。由于AsQueryable,ToList和Where的实现,Where()的工作速度更快。 AsQueryable只包含BindingList,它是ICollection,而ToList在ICollection中的工作速度比在Where返回的IEnumerable时要快。

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