据我所知,以不同顺序执行操作会产生不同的性能,例如以下慢查询之间的差异:
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方法调用会明显变慢吗?
此外,是否有任何其他编译器优化此查询可能会加速这个问题?
感谢您的想法和澄清! 布雷特
答案 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表包含条件中引用的其中一列的索引,则服务器可以选择使用索引,甚至避免查看与该特定条件部分不匹配的行。