Trending:
Software Development

EF Core 10 bulk operations cut database writes from 30 seconds to 50ms

Entity Framework Core 10's ExecuteUpdate and ExecuteDelete bypass change tracking to handle thousands of records in single SQL statements. For 10,000 updates, that's 300x faster than SaveChanges. Bulk inserts still need third-party libraries or batching strategies.

The problem every enterprise dev hits

You need to update 10,000 product prices. You write elegant LINQ, call SaveChanges(), and watch your ETL pipeline crawl. The culprit: EF Core loads every entity into memory, tracks changes, then fires individual UPDATE statements. For 10,000 records, that's 25-30 seconds of database round-trips.

EF Core 10 fixes this with ExecuteUpdate and ExecuteDelete. These methods bypass change tracking entirely, generating single SQL statements that run in 50-200ms.

What changed

The old approach loaded entities first:

var products = await context.Products.ToListAsync();
foreach (var p in products) { p.Price *= 1.1m; }
await context.SaveChangesAsync(); // 10,000 UPDATE statements

The new approach skips loading:

await context.Products
    .Where(p => p.CategoryId == 5)
    .ExecuteUpdateAsync(s => s
        .SetProperty(p => p.Price, p => p.Price * 1.1m));
// Single UPDATE statement

Benchmarks from April 2025 show 3-14x performance gains for 1,000-10,000 row operations. For bulk deletes, ExecuteDeleteAsync produces similar results: one DELETE statement instead of thousands.

The insert gap

Bulk inserts remain messier. EF Core 10's AddRange batches up to 1,000 rows per statement (down from 30+ seconds to 2-6 seconds for 10,000 records), but libraries like EFCore.BulkExtensions cut that to 270ms by using SqlBulkCopy or Postgres COPY under the hood.

The trade-off: these libraries add dependencies and commercial licensing for some providers. For operations under 1,000 rows, the overhead of temp tables often negates the benefit.

When to use what

ExecuteUpdate/Delete suit simple WHERE-based operations across SQL Server, Postgres, and other EF providers. They're native to EF Core 8+ (enhanced in 10) and ideal for APAC teams running multi-cloud setups. The catch: they can desync in-memory entities from database state if you're not careful with change tracking.

For inserts or complex graph operations, third-party libraries remain necessary. Set thresholds: use bulk methods above 1,000 rows, SaveChanges below.

What this means in practice

Enterprise apps processing nightly data loads or migrations now have built-in tools that don't require DbContext gymnastics. Government systems running batch reconciliations can cut processing windows significantly. The pattern works: write LINQ, let EF generate efficient SQL.

History suggests the real test comes when teams hit edge cases with related entities or distributed transactions. EF Core 10's transaction timeout handling for large datasets will matter more than raw speed for production workloads.