使用LINQ时谓词的顺序是否重要?

时间:2012-02-24 19:07:28

标签: c# .net performance linq optimization

据我所知,以不同顺序执行操作会产生不同的性能,例如以下慢查询之间的差异:

List<TestItem> slowResults = items.OrderBy(item => item.StringItem)
                                  .Where(item => item.IntItem == 100)
                                  .ToList();

这个更快的一个:

List<TestItem> fastResults = items.Where(item => item.IntItem == 100)
                                  .OrderBy(item => item.StringItem)
                                  .ToList();

但这不是我的问题:

我的问题是关于短路的性能,因为它与LINQ谓词有关。当我使用Where子句时,例如:

List<TestItem> results = items.Where(item => item.Item1 == 12 &&
                                             item.Item2 != null &&
                                             item.Item2.SubItem == 65 &&
                                             item.Item3.Equals(anotherThingy))
                              .ToList();

参数的顺序不重要吗?例如,我会期望首先执行.Equals会导致整体查询速度变慢,因为Item1 == 12整数评估是一个更快的操作?

如果订单确实重要,那有多重要?当然,像.Equals这样的调用方法可能会比我只是比较几个整数时的速度大得多,但是与LINQ运行的“慢”相比,这是一个相对较小的性能损失吗?由于LINQ进行大量的方法调用,就像.Equals真的重要 - 因为 - 除非它被覆盖 - 它将执行本机框架代码,对吧?另一方面,标准的MSIL方法调用会明显变慢吗?

此外,是否有任何其他编译器优化此查询可能会加速这个问题?

感谢您的想法和澄清! 布雷特

1 个答案:

答案 0 :(得分:13)

对于不同的LINQ提供商,答案会有所不同。特别是,LINQ to Objects和LINQ to Entities的故事非常不同。

在LINQ to Objects中,Where运算符接受过滤器为Func&lt; TSource,bool&gt;。 FUNC&LT;,&GT;是一个委托,所以为了讨论的目的,你可以把它想象成一个函数指针。在LINQ to Objects中,您的查询等同于:

static void Main() {
    List<TestItem> results = items.Where(MyFilter).ToList(); 

static boolean MyFilter(TestItem item) {
    return item.Item1 == 12 && 
        item.Item2 != null && 
        item.Item2.SubItem == 65 && 
        item.Item3.Equals(anotherThingy)
}

需要注意的主要事项是MyFilter是一种普通的C#方法,因此适用普通的C#规则,包括&amp;&amp;的短路行为。因此,将按您编写的顺序评估条件。 LINQ to Objects可以在不同的输入元素上调用MyFilter,但它不能改变MyFilter的功能。

在LINQ to Entities和LINQ to SQL中,Where运算符接受过滤器为 Expression&lt; Func&lt; TSource,bool&gt;&gt; 。现在,过滤器作为描述表达式的数据结构传递给Where运算符。在这种情况下,LINQ提供程序将查看数据结构(“表达式树”),由LINQ提供程序决定如何解释它。

在LINQ to Entities和LINQ to SQL案例中,表达式树将被转换为SQL。然后由数据库服务器决定如何执行查询。绝对允许服务器重新排序条件,它可以进行更实质的优化。例如,如果SQL表包含条件中引用的其中一列的索引,则服务器可以选择使用索引,甚至避免查看与该特定条件部分不匹配的行。