Fix Slow EF Core Queries with Projections
I’ve seen this happen a dozen times. An API endpoint is dog-slow, taking 2-3 seconds to respond. Everyone blames the network or the database. We check the query execution plan, and it’s fine—the database returns data in 50 milliseconds. So what’s the problem?
The problem is the 900KB of data we’re pulling from the database, serializing, and then throwing away for every single request. The culprit is a silent performance killer in Entity Framework Core: fetching full entities when you only need a few properties.
The Default Behavior is a Trap
It’s easy to write code like this. It’s clean, it’s simple, and it works.
var orders = await _dbContext.Orders
.Where(o => o.Status == "Active")
.ToListAsync();
But under the hood, EF Core is trying to be helpful by generating a SELECT *
style query. If your Orders
table has a few large NVARCHAR(MAX)
columns for notes, addresses, or serialized metadata, you’re in for a bad time.
Here’s the SQL it probably generates:
SELECT [o].[Id], [o].[CustomerId], [o].[OrderDate], [o].[Status],
[o].[Notes], [o].[ShippingAddress], [o].[BillingAddress],
[o].[InternalComments], [o].[AuditData], [o].[SerializedMetadata]
FROM [Orders] AS [o]
WHERE [o].[Status] = 'Active'
If your API only needs to display the order ID, customer name, and total, you just paid a heavy price in network I/O and memory allocation for nothing. That SerializedMetadata
column alone could be megabytes.
The Fix: Project Only What You Need
The …