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 →Repair Windows errors before they cause bigger problemsFix Now →iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more
EF Core 10 queries usually become faster when they make the database do less work: use the right indexes, return fewer rows and columns, avoid unnecessary roundtrips, and verify the generated SQL. EF Core runtime overhead matters, but it is rarely the first bottleneck. Start with a query plan and timings, then apply narrower ORM optimizations only where profiling shows a remaining cost.
EF Core 10.0 shipped 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. Microsoft recommends the latest patch of a supported release and testing major-version upgrades for breaking changes. See the EF Core releases and planning guidance.
Start with evidence, not micro-optimizations
Capture the SQL EF Core sends, the database execution plan, elapsed time, logical reads, rows returned, allocations, and the number of commands issued for one request. Test with production-like data volumes: a query that looks fine against a small development database can become expensive when it scans millions of rows or returns a large collection.
Free tools Windows power users keep installed
One-click scans. No signup required.
- Use your provider’s plan tool (for example, the execution-plan viewer in your database platform) to check for scans, expensive sorts, key lookups, and missing or unused indexes.
- Enable EF Core command logging in a non-production environment and count statements, parameters, and result sizes.
- Measure a representative request repeatedly, including network latency and concurrent activity; a local benchmark can hide roundtrip costs.
- Change one query shape at a time, then compare the plan and end-to-end result.
Microsoft’s efficient-querying documentation summarizes the priority well: “The main deciding factor in whether a query runs fast is whether it will properly utilize indexes where appropriate.”
#1 Best Overall
1. Make filters and ordering index-friendly
Inspect every predicate, join key, and OrderBy used by a hot query. An index that matches those operations can turn a table scan into a targeted seek. Indexes also consume storage and make inserts, updates, and deletes more expensive, so add them for a measured workload rather than for every column.
Check composite-index order
For an index on (A, B), a query filtering by A can generally use the leading portion of the index. A query filtering only by B generally cannot use that same index as efficiently. Put the column with the most useful leading restriction first for the actual query patterns, and include ordering columns when that avoids a separate sort.
Validate the plan after migration
Model configuration is not proof that the database will choose an index. Generate the SQL, run it with realistic parameters, and inspect the plan. Recheck plans after data growth because selectivity and statistics change over time.
Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstall2. Project only the columns the caller needs
Use Select to shape a result instead of materializing a full entity when the caller needs only a few fields. Projection reduces rows’ payload, network transfer, deserialization, and memory use.
var summaries = await db.Orders
.Where(o => o.CustomerId == customerId)
.Select(o => new OrderSummary
{
Id = o.Id,
PlacedAt = o.PlacedAt,
Total = o.Total
})
.ToListAsync();
A projection into a non-entity type is not a tracked mutable entity. If the operation must update an entity, load or attach it deliberately; do not assume a DTO projection will participate in normal change tracking.
3. Bound every result set
Combine a selective Where clause with Take (or a page size enforced by application policy) instead of calling ToListAsync on an unbounded query. This protects memory, response time, and network bandwidth when an unexpected data condition matches many rows.
var recent = await db.Events
.Where(e => e.TenantId == tenantId && e.CreatedAt >= cutoff)
.OrderByDescending(e => e.CreatedAt)
.Take(100)
.Select(e => new { e.Id, e.CreatedAt, e.Type })
.ToListAsync();
Make the limit explicit in APIs that expose search or history. If clients need more data, require pagination rather than silently increasing a single request’s maximum.
4. Choose offset or keyset pagination intentionally
Skip/Take offset pagination is easy to implement, but deep pages can require the database to process and discard many earlier rows. It can also produce duplicates or omissions when rows are inserted or deleted between requests.
| Approach | How it works | Advantages | Costs and risks |
|---|---|---|---|
| Offset | OrderBy(...).Skip(offset).Take(size) |
Direct page-number UI and simple random access | Work can grow with the offset; concurrent changes can shift page boundaries |
| Keyset (seek) | Filter on the last seen ordered key, then Take(size) |
Efficient sequential next/previous navigation and stable continuation | Requires a suitable index and a continuation token; jumping to page 50 is not natural |
For keyset pagination, order by a fully unique, indexed tuple (for example, timestamp plus ID) and request rows strictly after the last tuple. Pick the method that matches the navigation requirement instead of treating one as universally faster.
5. Eliminate accidental N+1 queries
Lazy loading can issue another database roundtrip each time code touches a navigation property. A loop over 500 parent entities can therefore send hundreds of additional commands. Log EF Core statements while exercising the endpoint to verify the command count.
Load known relationships deliberately
Use eager loading with Include when the relationship is known up front, or explicit loading when you need a controlled follow-up. Projecting a parent and the required child fields into one result shape can be even more efficient when entities are not being edited. Keep lazy loading disabled for paths where an accidental loop would be costly.
Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Fix the driver behind crashes, sound loss and screen glitches3Repair Windows errors before they cause bigger problems6. Filter and limit eager-loaded collections
If a parent needs only part of a collection, filtered eager loading keeps the relationship explicit while applying filtering, ordering, and limits inside the related query.
var blogs = await db.Blogs
.Include(b => b.Posts
.Where(p => p.IsPublished)
.OrderByDescending(p => p.PublishedAt)
.Take(5))
.ToListAsync();
This avoids transferring every child row merely because the parent navigation exists. Confirm the generated SQL and behavior for your provider, especially when combining multiple includes or tracking queries.
7. Compare single and split queries for collection includes
Joining multiple sibling collections in one SQL statement can multiply rows. Microsoft’s example shows one blog with 10 posts and 10 contributors producing 100 result rows because each post is paired with each contributor. The database and network transfer that repeated data even though EF Core later reconstructs the object graph.
| Choice | Database and network behavior | When it helps | Trade-offs |
|---|---|---|---|
| Single query (default for many include shapes) | One statement; sibling collection joins can create a cross product and duplicate parent columns | Fewer roundtrips and a consistent single SQL statement | Potentially many repeated rows, larger payloads, and expensive joins |
AsSplitQuery() |
Separate SQL statements for the root and included collections | Avoids the cross product for large sibling collections | Each query adds a network roundtrip; results can observe changes between statements and may require buffering |
var blogs = await db.Blogs
.Include(b => b.Posts)
.Include(b => b.Contributors)
.AsSplitQuery()
.ToListAsync();
Choose using measured row counts, latency, consistency requirements, and memory behavior. A split query is not automatically faster: on a high-latency connection, its extra commands may outweigh the savings from avoiding duplicated rows. The official trade-offs are documented in Single vs. Split Queries.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Rank #4
8. Use no-tracking for read-only work
Tracking maintains snapshots and identity information so changes can be detected and related entities can be fixed up. For a read-only endpoint, AsNoTracking removes that work when the result does not need to be edited through the context.
var products = await db.Products
.AsNoTracking()
.Where(p => p.IsActive)
.Select(p => new { p.Id, p.Name, p.Price })
.ToListAsync();
No-tracking can create separate object instances when the same database row appears multiple times. If read-only results need identity resolution without normal change tracking, evaluate AsNoTrackingWithIdentityResolution and benchmark its memory cost.
Microsoft’s sample that loads 10 blogs with 20 posts each measured 1,414.7 microseconds for tracking versus 993.3 microseconds for no-tracking. Those are figures from that particular benchmark, not a prediction for every provider, schema, or network.
9. Stream large results instead of buffering them
ToListAsync buffers the complete result set, so memory grows with the number of rows. Streaming processes rows as they arrive and is preferable when a response or pipeline can consume items incrementally.
await foreach (var row in db.LogEntries
.AsNoTracking()
.Where(x => x.CreatedAt >= cutoff)
.OrderBy(x => x.Id)
.AsAsyncEnumerable())
{
await ProcessAsync(row);
}
Keep the context and database connection alive for the duration of the enumeration, and do not start another operation on the same context before the current enumeration finishes. Buffer deliberately when you need random access, multiple passes, or a transaction boundary that requires all rows to be read first.
Best Value
10. Use asynchronous database APIs for scalable I/O
Call ToListAsync, FirstOrDefaultAsync, SaveChangesAsync, and related APIs in request paths that wait on database I/O. Async releases the request thread while the database and network are working, allowing the server to handle more concurrent requests. It does not make the database execution plan intrinsically faster, so keep query-shape and index work separate from scalability improvements.
Propagate cancellation tokens from the request to the EF Core call so abandoned requests do not continue consuming database resources. Avoid mixing synchronous and asynchronous calls on the same context, and never run two concurrent operations on one DbContext instance.
11. Benchmark context pooling and compiled queries only on hot paths
Context pooling
AddDbContextPool reuses context instances, reducing setup and allocation overhead. A pooled context is reset between uses, but application state that varies per request must be handled carefully. Tenant IDs, user-specific filters, and other mutable state must not leak between requests; configure or inject such state in a way compatible with pooling.
Recommended Free Tools
Compiled queries
Compiled queries bypass the normal query-cache lookup for a repeatedly executed query shape. They are most plausible for very hot paths with stable expression trees; they do not repair a missing index, excessive result set, or N+1 pattern.
In Microsoft’s 10-blog sample, a compiled query measured 645.3 microseconds and 13 KB allocated versus 709.8 microseconds and 18 KB for the non-compiled form. The documentation advises benchmarking on the target platform; treat these as sample results, not universal gains. See Advanced Performance Topics for pooling, query caching, and compiled-query considerations.
12. Check EF Core 10’s parameterized-collection SQL after upgrading
EF Core 10 defaults to translating parameterized collections into multiple scalar parameters. The change gives the query planner collection-cardinality information and can improve plans in many workloads, while balancing plan-cache reuse. Applications that relied on EF Core 8 or 9’s JSON-array translation can see different plans or regressions.
A safe upgrade workflow
- Capture generated SQL and representative parameter sizes before upgrading.
- Run the same workload on EF Core 10 and compare execution plans, logical reads, duration, and allocations.
- Test small, medium, and large collection parameters; a translation that works well for five values may behave differently for thousands.
- If a regression appears, evaluate the documented configuration or per-query translation controls for your database provider, then keep the choice that wins on production-like data.
Read the version-specific details in Microsoft’s EF Core 10 breaking changes documentation. EF Core 10 also adds first-class .NET 10 LeftJoin and RightJoin LINQ operators. They simplify query expressions; assume no speedup unless the generated SQL and database plan demonstrate one. Release features are listed in What’s New in EF Core 10.
Quick Recap
A practical tuning order for production incidents
- Identify the slow endpoint and capture command timings, SQL, parameters, row counts, and the database plan.
- Fix non-sargable filters, missing or misordered indexes, unnecessary joins, and avoidable sorts.
- Reduce transferred data with projection, result limits, and an appropriate pagination method.
- Count roundtrips; remove lazy-loading loops and decide between a single query, filtered include, projection, or split query.
- Choose tracking, no-tracking, streaming, and async semantics that match the endpoint’s behavior.
- Only after those changes, benchmark pooling or compiled queries on the hot path.
- After every EF Core or provider upgrade, compare generated SQL and plans, including parameterized-collection queries.
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.

