“Why is my LINQ query making 1001 database calls?” Usually, it is not the LINQ syntax itself. The N+1 query problem occurs when an application fetches a set of parent records in one query and then fetches related data separately as it processes each parent. With 1,000 parents, that can mean one query for the parents plus 1,000 more for their related data.
In Entity Framework Core, lazy loading can make those extra queries happen implicitly when code reads a navigation property. The fix depends on what data the operation needs: eager-load or project it when known in advance, load selectively when the need is conditional, and inspect the generated commands to confirm what the application actually sends.
As an Amazon Associate I earn from qualifying purchases.
What is the N+1 query problem in Entity Framework Core?
N+1 describes a pattern of database queries, not a special LINQ operator. The “1” is the query that loads the parent set; “N” is the additional query that can run for each parent when related data is accessed. Microsoft’s EF Core efficient-querying guidance describes this pattern and warns that lazy loading can produce unnecessary extra round trips.
For example, suppose an application loads 1,000 blogs, then reads each blog’s Posts navigation in a loop. If lazy loading is enabled and those navigations have not already been loaded, EF Core can issue one query for the blogs and one query for each blog’s posts: 1 + 1,000 = 1,001 queries. That arithmetic illustrates the pattern; it is not a benchmark, and not every LINQ loop behaves this way.
#1 Best Overall
The actual count depends on which navigations the code accesses, what data is already loaded, filters, the EF Core version and database provider, and how the application is written. In the documented proxy-based lazy-loading approach, proxies and virtual navigation properties are part of the setup; see Microsoft’s lazy-loading documentation.
How do I stop EF Core from running a query for every row?
Use eager loading when you know you need the related data
If the operation needs related records for the parent set, request them as part of the query with Include and, for deeper relationships, ThenInclude. Microsoft documents these patterns in its eager-loading guide.
Rank #2
- Used Book in Good Condition
var blogs = await context.Blogs
.Include(blog => blog.Posts)
.ToListAsync();
This makes the intended loading visible instead of relying on a property access later in a loop. For a read-only response that needs only selected values, a projection can avoid materializing full entities and unrelated columns:
var blogs = await context.Blogs
.Select(blog => new
{
blog.Url,
Posts = blog.Posts.Select(post => post.Title)
})
.ToListAsync();
A projection can fetch the fields and related values the operation needs; a filtered include can likewise constrain which related rows are loaded. The exact SQL, tracking behavior, and performance vary by EF Core version and provider, so verify the commands emitted by the application.
Use explicit loading when the need is conditional
Sometimes the application cannot know until later whether it needs a navigation, or only some parents need it. Explicit loading makes that database work visible at the point where the code requests it. It is still a separate query, however, so issuing an explicit load inside a loop for every parent can recreate N+1.
When you need only a subset of related records or a value such as a count, query the navigation rather than loading the full collection into memory. EF Core’s explicit-loading documentation shows querying navigation data and calculating aggregates.
Rank #4
var postCount = await context.Entry(blog)
.Collection(b => b.Posts)
.Query()
.CountAsync();
This asks the database for the count instead of retrieving every post. If the same operation is needed for many blogs, consider shaping a query that obtains the counts for the parent set together rather than repeating this request for each one.
Quick wins for a faster PC:
Clear out junk files and repair common Windows errorsFree Scan →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →Consider split queries when a joined result repeats too much data
Loading multiple collections in one joined query can repeat parent columns across many result rows, increasing the size of the result. EF Core supports split queries to retrieve related entities through separate SQL queries; Microsoft explains the trade-off in its querying performance guidance. For example:
var blogs = await context.Blogs
.Include(blog => blog.Posts)
.AsSplitQuery()
.ToListAsync();
A split query is not the same as the per-parent N+1 pattern: it divides a query involving included relationships into separate statements rather than issuing another load for every parent. But it does mean additional statements and round trips. Microsoft’s documentation describes the current implementation as performing a round trip for each query.
Separate executions can also observe intervening database changes. Microsoft’s EF Core 5.0 release notes discuss this consistency trade-off for split queries. A suitable serializable or snapshot transaction can mitigate that risk, but transaction isolation may carry performance costs. Check the behavior and APIs for the EF Core version and provider in use.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Which loading strategy should I choose?
| Approach | When it fits | Main trade-off |
|---|---|---|
Eager loading with Include or a projection |
The operation already knows it needs related data for the parent set. | A joined result can repeat parent columns; projection can limit fetched fields. Inspect the generated SQL and result shape. |
| Explicit or targeted loading | The need is conditional, or only selected parents need related data. | Each request still performs database work; repeating it per parent can produce N+1. Filter or aggregate in the database when that avoids loading a full collection. |
| Split query | A query with multiple included collections would produce costly row duplication. | It uses multiple statements and round trips, and separate executions may see intervening changes. |
Choose based on the rows and fields needed, not a blanket goal of minimizing the SQL statement count. A single large joined result can be less suitable than a small projection or a split query; conversely, repeated round trips can be especially costly when network latency is high. Microsoft’s ASP.NET Core 10.0 related-data tutorial recommends comparing approaches in the target application when performance matters.
How can I verify whether the loop causes N+1?
- Find the suspected access. Look for navigation-property reads such as
blog.Postsinside a loop, and check whether lazy loading or explicit per-parent loads are involved. - Inspect database commands. Use EF Core command logging or generated SQL to see how many statements run and whether a repeated query differs only by the current parent’s key.
- Compare query shapes. Run the operation with representative data before and after using a projection, eager load, targeted query, or split query. Compare statement count, returned rows and payload, and representative timings.
- Check real application conditions. Account for the database provider, network latency, data volume, concurrent changes, and any transaction isolation needed for consistency.
There is no universal time or percentage penalty for 1,001 queries: the impact depends on the application and its environment. Validate the actual commands and measure the alternatives under conditions representative of the workload.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.




