EF Core Isn't Slow: Five Query Patterns That Are
This article outlines five EF Core query patterns behind many slow pages, plus one habit that catches them all: read the SQL EF generates instead of judging the C# code. It covers N+1 queries, loading whole tables or unneeded columns, cartesian explosions from collection Includes, and filters that prevent index use. It is a practical checklist for anyone writing data access code.
Key points
- Log EF commands with optionsBuilder.LogTo, or call ToQueryString() to inspect the SQL without executing it.
- Avoid N+1 by disabling lazy loading and requesting only needed fields through Select projections.
- Apply filters before ToList(); once a DbSet is typed as IEnumerable<T>, Where runs in memory.
- Use AsNoTracking() or DTO projections for read-only queries to reduce tracking overhead.
- Multiple collection Includes can cause a cartesian explosion; AsSplitQuery() helps but adds round trips and loses snapshot consistency.
- Functions like ToLower() wrapped around a column can prevent index use; check the query plan when a page is slow.
Many slow EF Core pages are not caused by the C# code itself but by the SQL it produces. The article walks through five common query traps: N+1 round trips caused by lazy loading, filters applied after ToList() that pull a whole table into memory, unneeded columns and change tracking overhead, cartesian explosions from multiple collection Includes, and function calls such as ToLower() that stop an index from being used.
The author's main advice is to log the generated SQL, count the queries per page, and check the rows and columns being fetched. Projections, AsNoTracking(), AsSplitQuery() and keeping the query as IQueryable until the filter is applied are the fixes shown. The original includes concrete code samples and a benchmark figure worth reading in full.
Real-world use
- Debugging a slow list page by logging EF Core SQL and counting queries to find N+1 or full-table loads.
- Building read-only API endpoints that return only the columns the client needs through projections.
- Optimizing a user lookup by email so the query can use an index instead of wrapping the column in ToLower().
Why it matters
Reading the SQL EF Core generates lets you find performance problems by measurement instead of guesswork. Small changes in query shape can significantly cut query counts and memory use.