Skip to main content

Which linq method performs better: Where(expression).FirstorDefault() vs .FirstOrDefault(expression)

 Introduction

When it comes to LINQ, we always have multiple options to execute the query for the same scenario. Choosing correct one is always challenging aspect and debatable one. In one of our previous articles  Any Vs Count , we have done performance testing about best LINQ methods over .NET types. In this article, I would like to share about Where(expression).FirstorDefault() vs .FirstOrDefault(expression)

Approaches

Performance testing for Where(expression).FirstorDefault() vs .FirstOrDefault(expression) is very interesting
  • IEnumerable<T> or ICollcetion<T> .FirstOrDefault(expression) is better than Where(expression).FirstorDefault()

Public API

To check the performance, I need some amount of data which should already available. So I decided to choose this public api. Thanks to publicapis

Public API Models

Entry class

using System;
using System.Collections.Generic;
using System.Text;
 
namespace AnyVsCount
{
    public class Entry
    {
        public string API { get; set; }
        public string Description { get; set; }
        public string Auth { get; set; }
        public bool HTTPS { get; set; }
        public string Cors { get; set; }
        public string Link { get; set; }
        public string Category { get; set; }
    }
}

Root Collection

using System;
using System.Collections.Generic;
using System.Text;
 
namespace AnyVsCount
{
    public class RootCollection
    {
        public int count { get; set; }
        public ICollection<Entry> entries { get; set; }
    }
}
 

Root Enumerable

using System;
using System.Collections.Generic;
using System.Text;
 
namespace WhereVsFirstORDefault
{
    public class RootEnumerable
    {
        public int count { get; set; }
        public IEnumerable<Entry> entries { get; set; }
 
    }
}
 

IEnumerable<T> .FirstOrDefault(expression) is better than Where(expression).FirstorDefault()

Tick Count Based Approach IEnumerable<T>

For Where(Expression).FirstOrDefault() vs .FirstOrDefault(Expression) method comparisons we will  evaluate based on tick counts in executing the LINQ Statement. 

using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
 
namespace WhereVsFirstORDefault
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Who is better performer Where(expression).FirstorDefault() vs .FirstOrDefault(expression)(IEnumerable<T>)?");
            var client = new HttpClient();
            var response = await client.GetAsync("https://api.publicapis.org/entries");
            if (response.IsSuccessStatusCode)
            {
                var data = await response.Content.ReadAsStringAsync();
 
                var coll = JsonConvert.DeserializeObject<RootEnumerable>(data);
                //AdoptAPet
                Console.WriteLine("Evaluating Where(expression).FirstorDefault() Method:");
                Console.WriteLine("-----------------------");
 
                var watch1 = System.Diagnostics.Stopwatch.StartNew();
                // the code that you want to measure comes here
                var result1 = coll.entries.Where(x=>x.API.ToLower() == "AdoptAPet").FirstOrDefault();
                watch1.Stop();
                var elapsedMs1 = watch1.ElapsedTicks;
                Console.WriteLine("IEnumerable<T>.Where(expression).FirstorDefault() : " + elapsedMs1 + " Ticks");
 
                Console.WriteLine("-----------------------");
                Console.WriteLine(" ");
 
                Console.WriteLine("Evaluating FirstOrDefault(expression) Method:");
                Console.WriteLine("-----------------------");
 
                var watch2 = System.Diagnostics.Stopwatch.StartNew();
                // the code that you want to measure comes here
                var result2 = coll.entries.FirstOrDefault(x => x.API.ToLower() == "AdoptAPet"); 
                watch2.Stop();
                var elapsedMs2 = watch2.ElapsedTicks;
                Console.WriteLine("IEnumerable<T>.FirstOrDefault(expression) : " + elapsedMs2 + " Ticks");
 
                Console.WriteLine("-----------------------");
                Console.ReadKey();
            }
        }
    }
}
 

Debug Video IEnumerable<T>



IEnumerable<T> Performance Result

I repeat the same steps for several attempts and found IEnumerable<T>.FirstOrDefault(expression) is better performer than IEnumerable<T>.Where(Expression).FirstOrDefault()


Why IEnumerable<T>.FirstOrDefault(expression) is better performer than IEnumerable<T>.Where(Expression).FirstOrDefault()

FirstOrDefault(expression) will find for an item and stop its execution immediately when its found the element or item. In other case, Where(Expression).FirstOrDefault() will run first scan in identifying the item and then it will do additional scan to pick the element from the result of first scan. That's why .FirstOrDefault(Expression) is better than Where(Expression).FirstOrDefault().

Let's try ICollection<T>

ICollection<T> .FirstOrDefault(expression) is better than Where(expression).FirstorDefault()

using Newtonsoft.Json;
using System;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
 
namespace WhereVsFirstORDefault
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Who is better performer Where(expression).FirstorDefault() vs .FirstOrDefault(expression)(ICollection<T>)?");
            var client = new HttpClient();
            var response = await client.GetAsync("https://api.publicapis.org/entries");
            if (response.IsSuccessStatusCode)
            {
                var data = await response.Content.ReadAsStringAsync();
 
                var coll = JsonConvert.DeserializeObject<RootCollection>(data);
                //AdoptAPet
                Console.WriteLine("Evaluating Where(expression).FirstorDefault() Method:");
                Console.WriteLine("-----------------------");
 
                var watch1 = System.Diagnostics.Stopwatch.StartNew();
                // the code that you want to measure comes here
                var result1 = coll.entries.Where(x=>x.API.ToLower() == "AdoptAPet").FirstOrDefault();
                watch1.Stop();
                var elapsedMs1 = watch1.ElapsedTicks;
                Console.WriteLine("ICollection<T>.Where(expression).FirstorDefault() : " + elapsedMs1 + " Ticks");
 
                Console.WriteLine("-----------------------");
                Console.WriteLine(" ");
 
                Console.WriteLine("Evaluating FirstOrDefault(expression) Method:");
                Console.WriteLine("-----------------------");
 
                var watch2 = System.Diagnostics.Stopwatch.StartNew();
                // the code that you want to measure comes here
                var result2 = coll.entries.FirstOrDefault(x => x.API.ToLower() == "AdoptAPet"); 
                watch2.Stop();
                var elapsedMs2 = watch2.ElapsedTicks;
                Console.WriteLine("ICollection<T>.FirstOrDefault(expression) : " + elapsedMs2 + " Ticks");
 
                Console.WriteLine("-----------------------");
                Console.ReadKey();
            }
        }
    }
}
 

Debug Video ICollection<T>


ICollection<T> Performance Result


Conclusion

For both IEnumerable and ICollection types .FirstOrDefault(expression) is better performer than .Where(expression).FirstOrDefault(). Hope you like this article

Comments

Popular posts from this blog

How to resolve ASP.NET core web API 2 mins timeout issue

Introduction We are in the new world of microservices and cross-platform applications which will be supported for multiple platforms and multiple heterogeneous teams can work on the same application. I like ASP.NET Core by the way its groomed to support modern architecture and adhere to the software principles. I am a big fan of dot net and now I become the craziest fan after seeing the sophisticated facility by dot net core to support infrastructure level where we can easily perform vertical and horizontal scaling. It very important design aspect is to keep things simple and short and by the way, RESTFul applications are build and it is a powerful mantra for REST-based application and frameworks. Some times we need to overrule some principles and order to handle some situations. I would like to share my situation of handling HTTP long polling to resolve the ASP.Net core 2 mins issue. What is HTTP Long polling? In the RESTFul term, when a client asks for a query from the serv

How to Resolve ASP.NET Core Key Protection Ring Problem in AWS Lambda

Introduction When it comes to server less web application design using asp.net core razor pages, we definitely need to consider a factor of data protection key management and its lifetime in asp.net core. I developed a site using AWS toolkit of ASP.NET Core Razor Pages. The main advantage of ASP.NET Core is cross-platform from where we can deploy our application in MAC, Linux or windows. I deployed my site initially in IIS Server from which I got the results as expected .but later period I decided to host my site in AWS Lambda in order to meet our client requirement. Strangely, I got unexpected behavior from my site. I just refer the cloud information Lambda Log to identify or pinpoint the case, I got the error Information like “Error Unprotecting the session cookie” from the log. In this article, I tried to explain the root cause of the problem and its solution to overcome such kind of issue. Data Protection in ASP.NET Core This is feature in ASP.NET Core which acts as repl