COMPUTER ENGINEER

Jump to examples
Blog
Next.js / ASP.NET Core / SQL6 min study
28/ 41

Data layer and SQL

The N+1 problem, Include and AsNoTracking

The hidden cost of querying in a loop, and making read queries lighter.

UnderstandStudy an examplePractise

Understand the concept

The N+1 problem is running one query for a list and then one more query for each item in it. If each post’s author is loaded separately while listing 20 posts, 1 + 20 = 21 queries run. Each looks fast alone, but the network round trips add up, the page slows and the problem grows with data. It hides in development with little data and surfaces in production.

The fix is fetching related data in the same query. Include loads a navigation property with a JOIN. For reads, projection is usually better: using p.Author.Name inside Select lets EF Core emit a JOIN with only the needed columns.

By default EF Core tracks loaded entities for changes. For read-only data that wastes memory and CPU. AsNoTracking turns tracking off and is faster and lighter for read endpoints. The simulator’s ‘Slow list: N+1’ scenario shows the difference on the timing waterfall.

WHEN TO USE IT

N+1 is the most common ORM performance problem in production and easily missed when reading code.

COMMON PITFALL

Enabling lazy loading and touching navigation properties inside a loop.

LIVE ANIMATION

A letter’s journey through the city

Think of a request as a letter and the server as a city. Pick a scenario, press play and watch which gates the letter passes and where it gets stopped.

CLIENTEDGEWEB SERVERAPI · ASP.NET COREDATABrowserThe user’s screenNetworkDNS · TCP · TLSReverse proxyTLS termination, compressionNext.js serverSSR and route handlersKestrelHTTP serverException handlerMiddlewareRoutingEndpoint selectionRate limiterMiddlewareAuthenticationWho you areAuthorizationWhat you may doModel bindingHTTP → C# + validationControllerEndpoint codeServiceBusiness rules (DI)RedisDistributed cacheEF CoreLINQ → SQLSQL ServerQuery plan, indexes
OUTBOUND →

The blog page asks for 20 posts with their authors’ names.

BrowserYour screen. It writes the request and finally turns the answer into a page.
1 / 8
01 / PRACTICE

One topic. Three levels of depth.

Illustrative example
// ✗ N+1
var posts = await db.Posts.Take(20).ToListAsync(ct);
foreach (var p in posts)
    p.AuthorName = (await db.Authors.FindAsync(p.AuthorId))!.Name; // 20 ek sorgu

Every await in the loop is a database round trip.

This page connects to no real server or database. Code samples are illustrative for .NET 8, Next.js and SQL Server; timings are example values in the simulation, not measurements. Try samples only in your own development environment; never share real connection strings, tokens or passwords.

02 / YOUR TURN

Try it yourself first.

An orders page shows each order’s customer and items. For 50 orders the SQL log shows 101 queries. Which two relationships cause N+1, and how do you get to one query?

Show the solution and explanation
Worked solution
1 (siparişler) + 50 (müşteri) + 50 (ürünler) = 101
Düzeltme: projeksiyon
db.Orders.AsNoTracking().Select(o => new OrderView(
    o.Id, o.Customer.Name,
    o.Items.Select(i => i.Product.Name).ToList()))
// koleksiyon için AsSplitQuery() de değerlendirilebilir

Loading each relationship in a loop adds N queries. Projection turns relationships into JOINs; for large collections, split queries avoid cartesian explosion.