Performance Tuning with Microsoft Entity Framework Core

Boost your EF Core app with practical tips and real cases for faster queries, smarter models, and better performance.

Microsoft Entity Framework Core is a powerful Object-Relational Mapper (ORM) for .NET that simplifies database interactions using LINQ and C#. However, convenience can sometimes come at the cost of performance. As your application grows, inefficient queries, poor model configurations, and suboptimal database interactions can lead to serious performance bottlenecks.

This post will provide practical tips for optimizing EF Core performance. We’ll cover query tuning, model configuration, and execution strategies that help you unlock EF Core’s full potential in high-performance environments.

Optimize EF Core Queries

Read-Only Scenarios

EF Core’s change tracking mechanism is great for updates, but unnecessary for read-only data. Therefore, for read-only scenarios, add AsNoTracking() to your query.

var products = context.Products.AsNoTracking().ToList();

It’s useful to use AsNoTracking() in report modules where large read queries are executed and the data will not be updated. More about Tracking vs. No-Tracking Queries

Project Only Required Fields

Avoid pulling entire entities when only a few fields are needed using Select().

var productNames = context.Products.Select(
    p => new { p.Id, p.Name }
).ToList();

This reduces query payload size and improves speed, especially with large tables.

Filter Early, Avoid In-Memory Evaluation

Always apply filters before calling ToList(). Doing it after loads all data into memory.

// do this
var cheapProducts = context.Products
    .Where(p => p.Price < 50)
    .ToList();

// instead of this
var products = context.Products.ToList();
var cheapProducts = products.Where(p => p.Price < 50);

Use Compiled Queries for Hot Paths

For frequently executed queries, consider using compiled queries to skip parsing and translation steps.

private static readonly Func<AppDbContext, decimal, IEnumerable<Product>> _getCheapProducts = EF.CompileQuery((AppDbContext ctx, decimal price) =>
        ctx.Products.Where(p => p.Price < price));

var result = _getCheapProducts(context, 20m);

This should reduce CPU load in a high-traffic API that must execute the same query many times.

Tune Entity and Model Configuration

Indexing

Use [Index] attributes or Fluent API to create indexes on commonly queried columns.

[Index(nameof(Name))]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
}

The lack of indexes is a common performance issue in many databases, but the real problem only appears in high-load scenarios.

Configure Proper Field Types and Sizes

Set explicit column types to avoid “unlimited” database columns.

builder.Property(p => p.Name)
    .HasMaxLength(100)
    .IsRequired();

//it also can be model defined like
public class MyModel 
{
    [StringLength(100)]
    public string Name { get; set; }
}

This helps the database engine optimize storage and indexing.

Control Execution Strategies

Use Batching to Minimize Round Trips

Enable batching to combine multiple commands into a single round trip.

optionsBuilder.UseSqlServer(connectionString, opts => opts.MaxBatchSize(100));

Sometimes you need a huge data volume to be loaded into the database; in this case, the BatchSize could be helpful and the performance gain is visible.

Avoid Many Queries

Use eager loading properly to avoid repeated queries.

var orders = context.Orders
    .Include(o => o.Customer)
    .ToList();

You should use .Include instead of executing multiple queries. This will produce a join query and will bring all data at once.

Monitor Generated SQL

Use EF Core logging or .ToQueryString() to inspect SQL queries.

var query = context.Products.Where(p => p.Price > 100);
Console.WriteLine(query.ToQueryString()); //crude "log" example

Spotting issues early can help avoid costly full-table scans.

Conclusion

Entity Framework Core provides developer-friendly abstractions, but that ease of use can sometimes hide inefficiencies. By taking control of your queries, model configurations, and execution flow, you can greatly improve performance and resource usage in your applications.