Way, way back in 2007, the Language-Integrated Query (LINQ) was introduced as part of .NET 3.5. Since LINQ was new, I spent some time learning how to create the most performant queries, especially for Entity Framework. I learned back then how the query is written can affect performance. In this article, I will show the most performant way to write queries for a collection of objects.
The LINQ API & LAMBDA’S
In the beginning of LINQ API, this is how we wrote a simple where query:
var query = from person in PersonCollection
where person.Age.TotalDays > 1000
select person;
var result = query.ToList() // This runs the query
This same query can be written this way using a LAMBDA:
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).ToList();
Which one do you think is faster?
Any()
This LINQ Any() method returns a Boolean if there is even one item in the collection that meets the criteria. There are three ways to use Any().
// API
var query = from person in PersonCollection
where person.Age.TotalDays > 1000
select person;
var result = query.Any();
// LAMBDA'S
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).Any();
OR
var result = PersonCollection.Any(p => p.Age.TotalDays > 1000);
Performance
First() & FirstOrDefault()
The method First() returns the first item in the collection that meets the criteria while FirstOrDefault() will also return a default value. Below are the different ways to use these methods.
// API
var query = from person in PersonCollection
where person.Age.TotalDays > 1000
select person;
var result = query.First();
var result = query.FirstOrDefault();
// LAMBDA'S
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).First();
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).FirstOrDefault();
OR
var result = PersonCollection.First(p => p.Age.TotalDays > 1000);
var result = PersonCollection.FirstOrDefault(p => p.Age.TotalDays > 1000);
Performance
Last() & LastOrDefault()
The method Last() returns the last item in the collection that meets the criteria while LastOrDefualt() will also return a default value. Below are the different ways to use these methods.
// API
var query = from person in PersonCollection
where person.Age.TotalDays > 1000
select person;
var result = query.Last();
var result = query.LastOrDefault();
// LAMBDA'S
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).Last();
var result = PersonCollection.Where(p => p.Age.TotalDays > 1000).LastOrDefault();
OR
var result = PersonCollection.Last(p => p.Age.TotalDays > 1000);
var result = PersonCollection.LastOrDefault(p => p.Age.TotalDays > 1000);
Performance
As you can see, using Last() or LastOrDefault() as the first method in a LAMBDA call is much, much faster!
Summary
These benchmark results prove, without a doubt, that you should always use Any(), First(), FirstOrDefault, Last(), LastOrDefault or Where() at the beginning of a LAMBDA statement as shown below:
var result = PersonCollection.FirstOrDefault(p => p.Age.TotalDays > 1000);
I apologize if now you must go analyze your codebase for these methods and fix them if needed. It will increase the performance of your applications. If you have any comments, please make them below.
Pick up any books by David McCarter by going to Amazon.com: http://bit.ly/RockYourCodeBooks
Make a one-time donation
Make a monthly donation
Make a yearly donation
Choose an amount
Or enter a custom amount
Your contribution is appreciated.
Your contribution is appreciated.
Your contribution is appreciated.
DonateDonate monthlyDonate yearlyIf you liked this article, please buy David a cup of Coffee by going here: https://www.buymeacoffee.com/dotnetdave
© The information in this article is copywritten and cannot be preproduced in any way without express permission from David McCarter.
Regarding LINQ (Natual Query Integrated into the Language), it compiles to the SAME code as a Lambda written the same way, so the performance (of the same executing code) will be the same….
The real difference is where the predicate is places, in a call to the Where(…) extension method, or in the call to a method such as First(…). For simple collections [LINQ2SQL and LINQ2EF are difference beasts, as are other implementations), the Where(.,..) will transverse the entire collection passing the result set to the second; on the other hand, firstly using the predicate with First allows the processing to stop as soon the condition is met.
These effects would be the same, even if the code was written with explicit loops….
How did the query version compare to the first call?