Hardware FixRecommendedDevice not working? Your driver may be the problemCheck updates for common hardware issues.Fix DriversHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsSlow PC?RecommendedPC slow today? Run a repair scan before it gets worseResolve common Windows issues and optimize system performance.Scan Now×
FREEDOM251

Freedom251 › Blog › .NET 10

How to Speed Up EF Core 10 Queries: 12 Proven Performance Techniques

By Freedom251 Team · · 8 min read

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Fast EF Core 10 queries start with the database, not with micro-optimizing the ORM. Measure the generated SQL and execution plan first, then fix missing or mismatched indexes, excessive rows or columns, unnecessary roundtrips, and oversized result sets. Only after those issues are addressed should you consider narrower optimizations such as no-tracking queries, context pooling, or compiled queries.

EF Core 10.0 was released in November 2025 as a Long Term Support release supported through November 10, 2028. It requires the .NET 10 SDK to build and the .NET 10 runtime to run; it does not run on earlier .NET versions or .NET Framework. Use the latest patch of the supported release and test major-version upgrades for breaking changes (Microsoft EF Core releases and planning).

As an Amazon Associate I earn from qualifying purchases.

What actually determines EF Core 10 query speed?

EF Core translates LINQ into provider-specific SQL, sends that SQL to the database, receives rows across the network, and materializes objects. In most applications, the dominant costs are the database plan, disk or memory reads, rows and columns transferred, network latency, and the number of commands issued. EF Core’s own translation and materialization overhead matters, but it is usually a second-order problem.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Microsoft’s efficient-querying guidance puts the priority plainly: “The main deciding factor in whether a query runs fast is whether it will properly utilize indexes where appropriate.” Read the generated SQL, run it through your database’s execution-plan tools, and count commands emitted by a request before changing application code (Microsoft Learn: Efficient Querying).

How to optimize EF Core 10 queries: the 12 techniques

1. Start with execution plans and useful indexes

Check every frequent filter, join, and sort against the actual plan. A predicate on an unindexed column may force a scan, while a suitable index can seek directly to qualifying rows. Composite index order is significant: an index on (A, B) can generally support a query that starts with A, but it is not normally useful for a query filtering only on B.

Index only for a demonstrated workload. Indexes consume storage and make inserts, updates, and deletes more expensive because each affected index must also be maintained. Validate selectivity, sort order, included columns, and write volume with your database provider’s plan tools rather than adding indexes speculatively.

2. Project only the columns the caller needs

Fetching a complete entity when a screen needs three fields transfers unnecessary data and increases materialization work. Project to a small shape with Select:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
var cards = await db.Blogs
    .Where(b => b.IsPublished)
    .Select(b => new BlogCard(b.Id, b.Title, b.UpdatedAt))
    .ToListAsync();

Projection reduces the columns returned by SQL and therefore network traffic and memory use. A projection into a non-entity type is not a tracked, mutable entity update path; load or attach an entity explicitly when the operation must modify tracked state.

3. Bound the result set

Always express the business limit in SQL. Combine a selective Where clause with Take, and avoid materializing every matching row merely to discard most of them in application code:

var latest = await db.Orders
    .Where(o => o.CustomerId == customerId && o.Status == OrderStatus.Open)
    .OrderByDescending(o => o.CreatedAt)
    .Take(50)
    .ToListAsync();

A small development database can hide a production failure: a query returning a few dozen rows locally may return millions after deployment. Define a maximum page size and use an explicit “all rows” operation only when the data volume is known and intentional.

4. Pick offset or keyset pagination deliberately

Skip/Take offset pagination is easy to expose in an API, but deep pages require the database to walk past skipped rows and can become slower as the offset grows. It can also be vulnerable to duplicates or gaps when rows change between requests.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

For sequential next/previous navigation, keyset (seek) pagination uses the last seen ordering key:

var page = await db.Posts
    .Where(p => p.PublishedAt < lastPublishedAt
        || (p.PublishedAt == lastPublishedAt && p.Id < lastId))
    .OrderByDescending(p => p.PublishedAt)
    .ThenByDescending(p => p.Id)
    .Take(25)
    .ToListAsync();

Give the ordering columns a matching index and include a unique tie-breaker such as Id. Offset pagination remains appropriate when users jump to arbitrary page numbers or the result set is small.

5. Eliminate accidental N+1 queries

Lazy loading can send one query for the parent list and another query for each parent whose navigation property is touched. A loop over 500 entities can therefore create 501 roundtrips. Microsoft identifies lazy loading as particularly prone to this N+1 pattern (Efficient Querying).

If the relationships are known up front, eager-load them with Include, or load them explicitly in a controlled batch. Turn on statement logging in development and count commands for a representative request; a single LINQ expression does not guarantee a single database command when lazy loading is enabled.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

6. Filter eager-loaded collections

When a page needs only recent or top-rated children, do not load an entire collection and filter it in memory. Filtered eager loading supports filtering, ordering, and limiting inside the include:

var blogs = await db.Blogs
    .Include(b => b.Posts
        .Where(p => p.IsPublished)
        .OrderByDescending(p => p.PublishedAt)
        .Take(5))
    .ToListAsync();

This keeps the relationship loading explicit while reducing related rows. Verify the generated SQL and plan, especially when combined with other includes or provider-specific translation.

7. Compare single-query and split-query includes

Joining multiple sibling collections in one SQL statement can multiply rows before EF Core reconstructs the object graph. Microsoft’s example of one blog with 10 posts and 10 contributors can produce 100 result rows (10 × 10), even though only 20 related objects exist (Single vs. Split Queries).

Choice Database and transfer behavior Roundtrips and consistency When to investigate it
Single query (default in many cases) One command; sibling collection joins can create cartesian row multiplication and duplicate principal columns. Fewer network roundtrips; one statement’s result represents one database execution. Use when joins stay compact and the plan shows acceptable rows and payload.
AsSplitQuery() Separate SQL for included collections, avoiding the sibling cross product; principal data is not repeated for every combination. Each split query currently adds a network roundtrip. Results assembled from multiple queries can observe changes between statements, and buffering may be required. Test when collection joins produce excessive rows, memory use, or payload size.

Neither option is universally faster. Compare total rows, bytes, latency, memory, and consistency under concurrent updates on your provider and workload.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

8. Use no-tracking for read-only work

Change tracking performs identity management and change-detection work. For a query whose results will not be updated through the context, AsNoTracking can reduce CPU and allocation overhead:

var summaries = await db.Products
    .AsNoTracking()
    .Where(p => p.IsActive)
    .Select(p => new ProductSummary(p.Id, p.Name, p.Price))
    .ToListAsync();

Microsoft’s sample loading 10 blogs with 20 posts each measured 1,414.7 microseconds for tracking versus 993.3 microseconds for no-tracking. Those are Microsoft’s benchmark conditions, not a universal prediction (Efficient Querying). Plain no-tracking can create separate object instances when the same database row is referenced repeatedly; use identity resolution only when that semantic trade-off is worth its extra work.

9. Stream genuinely large result sets

ToListAsync buffers the complete result set, so memory grows with the number of rows and the size of each materialized object. For large exports or processing pipelines, stream rows and process each item as it arrives:

await foreach (var row in db.Events
    .AsNoTracking()
    .Where(e => e.OccurredAt > cutoff)
    .AsAsyncEnumerable())
{
    await HandleAsync(row);
}

Streaming limits peak application memory, but it does not make an inefficient SQL plan efficient. Keep the database-side filter and projection narrow, and ensure the consumer does not accidentally accumulate every streamed item.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

10. Use asynchronous database APIs for scalable I/O

Use ToListAsync, FirstOrDefaultAsync, SaveChangesAsync, and related APIs in request-handling code so a waiting database call does not block a worker thread. Async improves concurrency and throughput under I/O load; it does not intrinsically make the database execution faster. A slow plan, missing index, or high network latency remains slow when awaited asynchronously.

11. Treat pooling and compiled queries as hot-path optimizations

Context pooling reuses initialized DbContext instances and can reduce setup overhead. A pooled context must not retain request-specific state incorrectly: tenant IDs, user filters, and other mutable values need an explicit, safe reset or injection strategy before each use.

Compiled queries bypass EF Core’s query-cache lookup for a stable, frequently executed query shape. Microsoft’s 10-blog benchmark measured 645.3 microseconds and 13 KB allocated for a compiled query versus 709.8 microseconds and 18 KB for the non-compiled version. This is a sample on Microsoft’s platform; benchmark your target provider and deployment before adopting the added code complexity (Advanced Performance Topics).

Neither feature compensates for returning too many rows, missing indexes, cartesian joins, or excess roundtrips. Profile first and reserve them for measured hot paths.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

12. Inspect parameterized-collection SQL after upgrading to EF Core 10

EF Core 10 changes the default translation of parameterized collections to multiple scalar parameters. The approach gives the query planner collection-cardinality information while balancing plan-cache reuse and optimization. Applications that relied on EF Core 8 or 9 JSON-array translation can therefore see a different plan or performance profile.

When an upgrade coincides with a regression, capture the generated SQL, compare execution plans for realistic collection sizes, and test the documented configuration or per-query translation controls for your database provider (EF Core 10 breaking changes). Do not assume the new default is faster for every provider or parameter distribution.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

How should you measure an optimization?

  1. Capture the exact LINQ expression, generated SQL, parameter values or representative cardinalities, duration, allocated memory, and command count.
  2. Run the SQL through the database’s actual execution-plan tools and record logical reads, row counts, scans, seeks, sorts, and warnings.
  3. Test with production-scale data and realistic network conditions; a local small database can conceal result-size and latency problems.
  4. Change one factor, such as an index, projection, include strategy, or tracking mode, and rerun the same workload.
  5. Check correctness under concurrent writes, especially when changing pagination or using split queries.
  6. Keep an optimization only when its measured gain outweighs its maintenance and implementation cost.

What changed in EF Core 10 besides performance settings?

.NET 10 adds first-class LINQ LeftJoin and RightJoin operators. They simplify query expressions, but they are not a performance feature by themselves; speed still depends on the SQL generated and the database plan (What’s New in EF Core 10).

For upgrades, use the latest patch of EF Core 10, review the documented breaking changes, and test provider-specific behavior rather than assuming EF Core 8 or 9 execution characteristics remain unchanged (EF Core releases and planning).

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A practical tuning order for a slow query

  1. Confirm the query is needed and identify its command count.
  2. Inspect SQL and the execution plan; fix predicates, joins, ordering, and indexes first.
  3. Project only required columns and impose a safe result limit.
  4. Choose keyset pagination for sequential navigation or offset pagination for random page access.
  5. Remove N+1 behavior and compare filtered includes with explicit loading.
  6. Evaluate single versus split queries for collection graphs.
  7. Choose tracking, no-tracking, or identity resolution according to update and reference semantics.
  8. Stream large results and use async APIs for server scalability.
  9. Only after profiling, test pooling or compiled queries on the hot path.
  10. After an EF Core 10 upgrade, re-check parameterized collections and provider plans.

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.

.NET 10C++database performanceEF Core 10Entity Framework Corequery optimizationSQL

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Recommended PC Tool
Recommended PC Tool
PC Slower Than It Used to Be?Free scan - under a minute
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.