EF Core performance optimization

EF Core performance optimization

Entity Framework Core (EF Core) performance optimization is about reducing database load, minimizing memory usage, and improving query execution time while keeping your code maintainable.

Below is a practical, developer-focused guide covering core components, best practices, examples, and alternatives.

What affects EF Core performance?

At a high level, performance depends on:

• Query generation (LINQ → SQL translation)
• Database round-trips
• Change tracking
• Data size (over-fetching)
• Index usage in the database
• Context lifetime and configuration

Required / Key Components

1. DbContext configuration

Controls tracking, pooling, logging, etc.

options.UseSqlServer(connectionString)
       .UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);

2. Database provider

EF Core performance depends heavily on provider:

• SQL Server
• PostgreSQL
• SQLite

Each has different query capabilities and optimizations.

3. Indexes (database-level)

EF Core doesn’t replace proper indexing.

modelBuilder.Entity()
    .HasIndex(u => u.Email);

4. Logging & profiling tools

To detect slow queries:

• EnableSensitiveDataLogging()
• SQL logs
• Database execution plans

EF Core Best Practices

1. Use AsNoTracking() for read-only queries

Tracking adds overhead.

var users = await context.Users
    .AsNoTracking()
    .ToListAsync();

Use when you don’t update entities

2. Select only what you need

Avoid loading full entities unnecessarily.

Bad practice:

var users = await context.Users.ToListAsync();

Good practice:

var users = await context.Users
    .Select(u => new { u.Id, u.Name })
    .ToListAsync();

3. Avoid N+1 queries (use eager loading)

Bad practice:

var orders = context.Orders.ToList();
foreach (var order in orders)
{
    var items = context.OrderItems
        .Where(i => i.OrderId == order.Id)
        .ToList();
}

Good practice:

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

4. Use compiled queries for hot paths

Reduces LINQ translation overhead.

static readonly Func<MyContext, int, Task> _getUserById =
    EF.CompileAsyncQuery((MyContext ctx, int id) =>
        ctx.Users.FirstOrDefault(u => u.Id == id));

5. Use pagination (Skip / Take)

Never load large datasets at once.

var users = await context.Users
    .OrderBy(u => u.Id)
    .Skip(100)
    .Take(50)
    .ToListAsync();

6. Disable lazy loading (usually)

Lazy loading often causes hidden queries.

// Avoid enabling proxies unless necessary

7. Batch updates instead of looping

Bad practice:

foreach (var user in users)
{
    user.IsActive = false;
}

await context.SaveChangesAsync();

Better practice (EF Core 7+):

await context.Users
    .Where(u => u.LastLogin < DateTime.Now.AddYears(-1))
    .ExecuteUpdateAsync(u => u.SetProperty(x => x.IsActive, false));

8. Use connection pooling / DbContext pooling

services.AddDbContextPool(options =>
    options.UseSqlServer(connectionString));

9. Optimize SaveChanges

Use fewer calls
Wrap in transactions when needed

10. Use proper data types

Avoid mismatches (e.g., string vs int keys)

Example: Optimized Query

var result = await context.Orders
    .AsNoTracking()
    .Where(o => o.Status == "Completed")
    .OrderByDescending(o => o.CreatedAt)
    .Select(o => new
    {
        o.Id,
        o.Total,
        CustomerName = o.Customer.Name
    })
    .Take(20)
    .ToListAsync();

• No tracking
• Projection
• Limited result set
• Efficient SQL

Common Performance Mistakes

• Loading entire tables into memory
• Ignoring indexes
• Overusing Include
• Using synchronous calls (ToList() instead of ToListAsync)
• Keeping DbContext alive too long
• Multiple SaveChanges() in loops

Alternatives to EF Core

Depending on your performance needs:

1. Dapper

• Very fast (close to raw SQL)
• Less abstraction
• Best for read-heavy scenarios

2. Raw ADO.NET

• Maximum control
• More boilerplate

3. NHibernate

• Mature ORM with advanced caching
• More complex than EF Core

4. Hybrid approach

• EF Core for writes
• Dapper for reads

When EF Core is enough vs not?

EF Core is great when:

• You want productivity + maintainability
• Medium-scale applications
• Complex domain models

Consider alternatives when:

• Ultra-high throughput (millions of queries/sec)
• Tight latency requirements
• Heavy reporting queries

Advanced Techniques

• Second-level caching libraries
• Split queries (AsSplitQuery)
• Query tags for debugging
• Database-side stored procedures

Contents related to 'EF Core performance optimization'

Entity Framework (EF)
Entity Framework (EF)
Hibernate ORM
Hibernate ORM
Language-Integrated Query (Linq)
Language-Integrated Query (Linq)