Is the following request automatically "optimized" ?
var result = initial
.Where(Predicate1)
.Where(Predicate2)
.Where(Predicate3);
This is equivalent to
var result = initial
.Where(e => Predicate1(e) && Predicate2(e) && Predicate3(e));
Which one of these statements is the more optimized of the two? Or are they identical?
A where clause will generally increase the performance of the database. Generally, it is more expensive to return data and filter in the application. The database can optimize the query, using indexes and partitions. The database may be running in parallel, executing the query in parallel.
The OR operator is used to combine multiple conditions in an SQL statement's WHERE clause.
You can specify multiple conditions in a single WHERE clause to, say, retrieve rows based on the values in multiple columns. You can use the AND and OR operators to combine two or more conditions into a compound condition.
The order in which columns appear in the WHERE clause does not affect query efficiency. Only the order of columns when defining the index matters.
Although the compiled code does not combine the predicates, the execution essentially does. Linq's Where method returns a WhereListIterator when passed a List. The WhereListIterator has its own Where method implementation that returns a new WhereListIterator with the predicates combined. It looks like this:
return new Enumerable.WhereListIterator<T>(this.source, Enumerable.CombinePredicates<T>(this.predicate, predicate)
where this.source is the List, this.predicate is the predicate of the first Where, and predicate is from the second Where.
The CombinePredicates returns a delegate containing the following code:
if (predicate1(source)) return predicate2(source);
return false;
So the chained Where clauses should end up with something like:
if (predicate1(source)) {
if (predicate2(source) {
return predicate3(source) {
}
return false;
}
return false;
With a small list, using && to combine the predicates in a single Where is likely more efficient, but as the list size increases the runtime of the two options may become similar. You would have to profile it to quantify just what the difference is. I suspect it's not large enough to matter much.
No, it's not. These Where
methods calls are not combined into one.
c# code:
var input = new List<string>();
var output = input.Where(x => x.StartsWith("test")).Where(x => x.Length > 10).Where(x => !x.EndsWith("test"));
IL generated:
IL_0000: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
IL_0005: stloc.0
IL_0006: ldloc.0
IL_0007: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_000c: brtrue.s IL_001f
IL_000e: ldnull
IL_000f: ldftn bool ConsoleApplication2.Program::'<Main>b__0'(string)
IL_0015: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_001a: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_001f: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0024: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_0029: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_002e: brtrue.s IL_0041
IL_0030: ldnull
IL_0031: ldftn bool ConsoleApplication2.Program::'<Main>b__1'(string)
IL_0037: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_003c: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_0041: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate4'
IL_0046: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_004b: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0050: brtrue.s IL_0063
IL_0052: ldnull
IL_0053: ldftn bool ConsoleApplication2.Program::'<Main>b__2'(string)
IL_0059: newobj instance void class [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
IL_005e: stsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0063: ldsfld class [mscorlib]System.Func`2<string, bool> ConsoleApplication2.Program::'CS$<>9__CachedAnonymousMethodDelegate5'
IL_0068: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
IL_006d: pop
IL_006e: ret
As you can see, there are 3 System.Linq.Enumerable::Where<string>
calls.
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