I understand that executing operations in different orders will yield different performance such as the difference between the following slow query:
List<TestItem> slowResults = items.OrderBy(item => item.StringItem)
.Where(item => item.IntItem == 100)
.ToList();
and this faster one:
List<TestItem> fastResults = items.Where(item => item.IntItem == 100)
.OrderBy(item => item.StringItem)
.ToList();
But that is not my question:
My question is about performance of the short circuiting as it relates to a LINQ predicate. When I use a Where clause, like in this case:
List<TestItem> results = items.Where(item => item.Item1 == 12 &&
item.Item2 != null &&
item.Item2.SubItem == 65 &&
item.Item3.Equals(anotherThingy))
.ToList();
Doesn't the order of the arguments matter? For instance, I would expect that doing a .Equals first would result in a slower query overall due to the Item1 == 12 integer evaluation being a much faster operation?
If order does matter, how much does it matter? Of course, calling methods like .Equals probably results is a much larger slow-down than if I was just comparing a few integers, but is it a relatively small performance penalty compared to how 'slow' LINQ operates? As LINQ makes tons of method calls, is something like .Equals really going to matter since--unless its overridden--it'll be executing native framework code, right? On the other hand, is a standard MSIL method call going to be significantly slower?
Also, are there any other compiler optimizations on this query which might be speeding this up under the hood?
Thanks for the thoughts and clarification! Brett
In LINQ, the OrderBy operator is used to sort the list/ collection values in ascending order. In LINQ, if we use order by the operator by default, it will sort the list of values in ascending order. We don't need to add any ascending condition in the query statement.
A predicate, or more precisely a predicate functor, is a Boolean-valued function. It is often a unary function, checking one argument against a condition and returning the result. Disregarding functions depending on side effects, there are two nullary functions (without arguments). public static class Predicate.
LINQ includes five sorting operators: OrderBy, OrderByDescending, ThenBy, ThenByDescending and Reverse. LINQ query syntax does not support OrderByDescending, ThenBy, ThenByDescending and Reverse. It only supports 'Order By' clause with 'ascending' and 'descending' sorting direction.
The answer is going to be different for different LINQ providers. In particular, the story is very different for LINQ to Objects and say LINQ to Entities.
In LINQ to Objects, the Where operator accepts the filter as Func<TSource, bool>. Func<,> is a delegate, so for the purposes of this discussion, you can think of it as a function pointer. In LINQ to Objects, your query is equivalent to this:
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)
}
The main thing to notice is that MyFilter is an ordinary C# method and so ordinary C# rules apply, including the short-circuiting behavior of &&. Consequently, the conditions will be evaluated in the order you wrote them. LINQ to Objects can invoke MyFilter on different input elements, but it cannot change what MyFilter does.
In LINQ to Entities and LINQ to SQL, the Where operator accepts the filter as Expression<Func<TSource, bool>>. Now, the filter is passed into the Where operator as a data structure that describes the expression. In that case, the LINQ provider will look at the data structure (the "expression tree") and it is up to the LINQ provider to decide how to interpret it.
In LINQ to Entities and LINQ to SQL cases, the expression tree will be translated to SQL. And then it is up to the database server to decide how to execute the query. The server is definitely allowed to reorder the conditions, and it may do even more substantial optimizations. For example, if the SQL table contains an index on one of the columns referenced in the condition, the server can choose to use the index and avoid even looking at rows that don't match that particular condition part.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With