0

I have the following LINQ query:

Person
    .OrderBy(x => x.FirstName)
    .Where(x => x.FirstName.Contains("a"));

I can also write this query in the following way:

Person
    .Where(x => x.FirstName.Contains("a"))
    .OrderBy(x => x.FirstName);

Both of them have the same result. So here's my question, What is the difference between the two queries? Which one is better? And why?

Persian Brat
  • 394
  • 2
  • 13
  • 4
    It depends. If it is query to the database then generated SQL should be the same i.e. performance will be the same also. In case of LINQ to Objects filtering first in general should be faster, also note that in theory `Where` does not guarantee order, so it also can lead to different results. – Guru Stron Nov 19 '21 at 20:30
  • Depends on the data. How much is it already sorted by FirstName and how many 'a's are contained. Where will always check each item once. OrderBy might check some items multiple times. – lidqy Nov 19 '21 at 20:33
  • Also see [this](https://stackoverflow.com/q/69774817/2501279) – Guru Stron Nov 19 '21 at 20:34

1 Answers1

4

If you use Linq-To-Entities(or whatever database provider), there might be no difference at all, because the database will take care of the optimization. But in general and especially with Linq-To-Objects the latter is better, because it is more efficient to order less.

Also Guru is right with his comment that the result could be different in theory. Enumerable.Where does not guarantee the order in the documentation. But they won't change it because they would break a lot of code(it's mentioned here that the order ist stable if the input sequence was ordered). Edit: Actually some providers already change that order arbitrarily(for example PLINQ).

I have asked a similar question long time ago which answer you might find helpful: Order of LINQ extension methods does not affect performance? Note that it's just about Linq-To-Objects.

Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
  • *"the result could be different, at least in theory"*: only in theory, in fantasy and in fiction, about a future Microsoft that has being infiltrated by evil forces. In which scenario there is no guarantee about anything anyway. Let's be realistic, and don't throw warnings about things that are never expected to happen. – Theodor Zoulias Nov 19 '21 at 21:07
  • @TheodorZoulias: i can always implement my own collection which enumerator's `Current` property returns an arbitrary/randon item. In that case `Where` will also get a random item. If i reverse the order and use `Where...OrderBy` it is guaranteed, no matter what type of sequence you enumerate. – Tim Schmelter Nov 19 '21 at 22:39
  • Tim I think that the comparison is between `.OrderBy().Where()` and `.Where().OrderBy()`, and the warning is about these two sequences containing the same items in different order, in some hypothetical future LINQ implementation. My point is that the warning is superficial. Of course if you omit the `OrderBy`, the order will be whatever the `Person` sequence emits by itself. – Theodor Zoulias Nov 19 '21 at 22:41
  • @TheodorZoulias: well, i have mentioned in my answer that it's just a theoretical issue because MS did not want to gurantee the order as they do in other methods. So feel free to ignore that because it's not a warning("they won't change it because they would break a lot of code"). I saw Guru's comment and wondered if he's right – Tim Schmelter Nov 19 '21 at 22:44
  • Tim the [`Select`](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.select) operator makes no explicit guarantee about the order of the items in the projected sequence either. Should we include this warning everytime we see someone using the `Select` operator? *"Theoretically the projected items can be in any random order, but don't worry, Microsoft won't do it."* It seems kind of excessive to me. Just saying. – Theodor Zoulias Nov 19 '21 at 22:56
  • 1
    @TheodorZoulias These are absolutely not guaranteed to be the same results. `OrderBy` is *by contract* (according to the docs of the interface) guaranteed to return results in the order specified, but `Where` has no such contract, ergo a particular implementation is allowed to return them in any order (eg a parallelizing implementation). The point of the warning is that these two results are *not* the same, even though they look similar at a superficial glance. Obviously `Select` would have no such expectation, even by a superficial reader of the code. – Charlieface Nov 20 '21 at 20:42
  • @Charlieface could you clarify this sentence? *"Obviously Select would have no such expectation, even by a superficial reader of the code."* Do you mean that it's more expected for the `Where` to change the order of the elements in the sequence than the `Select`? If yes, why? – Theodor Zoulias Nov 20 '21 at 20:53
  • @TheodorZoulias No the opposite: a superficial reader of code with just a `Select()` would have no expectation that elements would return in *any* specific order. Whereas `OrderBy().Where()` might cause a superficial reader to think there is an ordering specified, when there is not. As mentioned, `Enumerable` Linq-to-Objects doesn't in practice change ordering, but for example `Parallel` can, and so could other Linq providers. – Charlieface Nov 20 '21 at 20:56
  • @Charlieface personally my expectation about the order preservation of `.OrderBy().Select()` is extremely high, and equally high with my expectation about the order preservation of `.OrderBy().Where()`. Regarding the behavior of PLINQ not preserving the order by default, and requiring the `AsOrdered` operator to do so, I consider it a poor decision that has thrown countless programmers in the pit of failure (myself included). Microsoft didn't repeat this mistake when they released the TPL Dataflow library. The `EnsureOrdered` option is `true` by default in this library. – Theodor Zoulias Nov 20 '21 at 21:21
  • @TheodorZoulias: the point is: why you want to use `.OrderBy().Where()` instead of `.Where().OrderBy()` if you gain a less efficient query with undefined order? Someone might use the same query later with PLINQ and get a different result without even noticing. So you get nothing but troubles. – Tim Schmelter Nov 20 '21 at 22:55
  • Tim I don't deny that the `.Where().OrderBy()` is more efficient than the `.OrderBy().Where()`. What I am challenging is the idea that worrying about a future LINQ implementation having a non-order-preserving `Where` behavior is realistic. Regarding the possibility of using the same operators as part of a PLINQ query, actually it makes no difference either ([fiddle](https://dotnetfiddle.net/S2VTDB)). The `OrderBy` PLINQ operator returns an `OrderedParallelQuery` object. – Theodor Zoulias Nov 20 '21 at 23:14
  • @TheodorZoulias: "my expectation about the order preservation of .OrderBy().Select() is extremely high, and equally high with my expectation about the order preservation of .OrderBy().Where()". Your expectations can be high with the former but should not be queally high with the latter. As mentioned before, there is no guarantee that `Where` keeps the input sequence in order and actually some providers change that order arbitrarily(for example [PLINQ](https://learn.microsoft.com/en-us/dotnet/standard/parallel-programming/order-preservation-in-plinq)). – Tim Schmelter Jan 03 '22 at 10:53