The EF Core Tips to Enhance Read Performance with AsNoTracking() will be covered in this post. Let's begin now. AsNoTracking() is one of the simplest ways to improve speed for read-intensive activities when working with Entity Framework Core (EF Core). Applications such as dashboards, reporting systems, and APIs can benefit greatly from this minor adjustment.
The Problem: Default Tracking Adds Overhead
By default, EF Core tracks every entity it retrieves. This allows it to:
- Detect changes
- Automatically persist updates using SaveChanges()
However, this tracking comes at a cost:
- Extra memory usage
- Additional CPU overhead
- Slower query performance for large datasets
If you're only reading data, this tracking is unnecessary.
The Solution: AsNoTracking()
AsNoTracking() tells EF Core:
“Fetch the data, but don’t track it in the DbContext.”
Example Scenario
Let's say you're building a Product API that returns a list of active products.
Without AsNoTracking()
public async Task<List<Product>> GetActiveProducts()
{
return await _context.Products
.Where(p => p.IsActive)
.ToListAsync();
}
Issues
- EF Core tracks all retrieved Product entities.
- Unnecessary overhead if you're just displaying data.
With AsNoTracking()
public async Task<List<Product>> GetActiveProducts()
{
return await _context.Products
.AsNoTracking()
.Where(p => p.IsActive)
.ToListAsync();
}
Benefits
- Faster execution
- Reduced memory consumption
- Better scalability for high-load APIs
Real-World Use Case
Imagine a dashboard showing:
- Recent orders
- Customer lists
- Sales reports
All of these are read-only views.
public async Task<List<OrderDto>> GetRecentOrders()
{
return await _context.Orders
.AsNoTracking()
.OrderByDescending(o => o.CreatedDate)
.Select(o => new OrderDto
{
Id = o.Id,
CustomerName = o.Customer.Name,
TotalAmount = o.TotalAmount
})
.ToListAsync();
}
This avoids tracking thousands of rows unnecessarily and keeps your API responsive.
Important Caveat
Entities retrieved using AsNoTracking() are not tracked, so changes won’t be saved automatically.
This Will NOT Work
var product = await _context.Products
.AsNoTracking()
.FirstAsync(p => p.Id == 1);
product.Price = 100;
await _context.SaveChangesAsync(); // No update!
Correct Approach
_context.Products.Update(product);
await _context.SaveChangesAsync();
or fetch the entity without AsNoTracking() if you intend to update it.
When Should You Use It?
Use AsNoTracking() When
- Data is read-only
- You're building GET APIs
- Query returns large datasets
- Performance optimization is critical
Avoid When
- You plan to update the entity
- You rely on automatic change tracking
- Complex graph updates are involved
Pro Tip: Make No-Tracking the Default
If most of your queries are read-only:
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
You can still override per query:
context.Products.AsTracking().FirstOrDefaultAsync();
Advanced: Identity Resolution
AsNoTrackingWithIdentityResolution()
Avoids tracking
Ensures same entity instance is reused within query results
Useful For
- Complex joins
- Related entity graphs
Summary
- AsNoTracking() is a low-effort, high-impact performance optimization.
- Ideal for read-only queries and APIs.
- Reduces memory usage and execution time.
- Avoid using it when updates are required.
Final Thought
If your application is read-heavy (which most modern apps are), start using AsNoTracking() consistently—it’s one of the simplest ways to scale EF Core efficiently.
Conclusion
In this article, I have tried to cover EF Core Tips to Improve Read Performance with AsNoTracking().
European Best, cheap and reliable ASP.NET Core 10.0 hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.
