How to optimize Entity Framework Core queries

Entity Framework Core is an Object-Relational Mapping (ORM) tool, which means it enables developers to interact with a database using object-oriented programming techniques rather than writing raw SQL queries.

However, despite its convenience, using EF Core can sometimes lead to inefficient database queries, resulting in performance issues for the application.

Here are some tips to help you optimize Entity Framework Core database queries:

  • Use eager loading for related entities: By using Include() or ThenInclude() methods, you can eagerly load related entities in a single query instead of triggering multiple queries for each related entity.

// Inefficient query without eager loading
var author = dbContext.Authors.FirstOrDefault(a => a.Id == authorId);
var books = dbContext.Books.Where(b => b.AuthorId == authorId).ToList();
// Optimized query with eager loading
var author = dbContext.Authors.Include(a => a.Books).FirstOrDefault(a => a.Id == authorId)
  • Projection using Select(): Only select the required properties using the Select() method to reduce the amount of data fetched from the database.

// Inefficient query without projection
var books = dbContext.Books.ToList();
// Optimized query with projection
var books = dbContext.Books.Select(b => new { b.Id, b.Title }).ToList();
  • Avoid the N+1 problem: Be cautious of the N+1 problem, which occurs when you have to execute N additional queries to fetch related data for each item in a collection. Use Include() or ThenInclude() to fetch all the required data in a single query.

// Inefficient query with N+1 problem
var authors = dbContext.Authors.ToList();
foreach (var author in authors)
{
var books = dbContext.Books.Where(b => b.AuthorId == author.Id).ToList();
}
// Optimized query with eager loading
var authors = dbContext.Authors.Include(a => a.Books).ToList();
  • Use AsNoTracking() for read-only operations: If you're only reading data and not modifying it, use AsNoTracking() to avoid entity tracking overhead.

// Without AsNoTracking (entity tracking enabled)
var book1 = dbContext.Books.FirstOrDefault(b => b.Id == 1);
book1.Title = "Updated Title";
dbContext.SaveChanges();
// With AsNoTracking (entity tracking disabled)
var book2 = dbContext.Books.AsNoTracking().FirstOrDefault(b => b.Id == 1);
  • Batch database operations: When performing bulk inserts, updates, or deletes, use batch operations to minimize the number of database roundtrips.

// Inefficient way of inserting multiple records
foreach (var book in newBooks)
{
dbContext.Books.Add(book);
dbContext.SaveChanges();
}
// Efficient batch insert
dbContext.Books.AddRange(newBooks);
dbContext.SaveChanges();
  • Indexing: Analyze the query patterns in your application and create appropriate indexes on the database tables to speed up query execution. Use tools like SQL Server Query Execution Plan to analyze query performance.

  • Split queries: In some scenarios, it may be beneficial to split complex queries into multiple smaller queries, especially when dealing with large datasets.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved