.NET 10 EF vs SQL SCript Performance
.NET 10 EF vs SQL SCript Performance
Benchmark Setup
To keep things consistent, I used the following configuration:
Iteration Strategy
BenchmarkDotNet automatically adjusts iteration counts:
Fast operations: around 100 iterations
Medium operations: 15 to 50 iterations
Slower operations: 10 to 15 iterations
Test Parameters
100 database records for EF Core tests
Azure SQL / LocalDB and SQLite providers
Identical operations across EF Core and raw SQL paths
Measurements include execution time and memory allocation
What I Compared
The goal was simple:
Compare EF Core 10 LINQ queries with:
Stored Procedures (Azure SQL / LocalDB)
Parameterized SQL using Dapper (SQLite)
Across common operations:
Insert
Bulk Insert
Update
Delete
GetById
GetByCategory
GetTop100
Complex queries
Results: Azure SQL / LocalDB
Hereβs where things get interesting.
Azure SQL / LocalDB (EF Core 10 vs Stored Procedures)
| Operation | EF Core 10 Mean | SP/Dapper Mean | SP Advantage | EF Allocated | SP Allocated |
|---|---|---|---|---|---|
| BulkInsert | 2,372,819.89 ns | 10,075,352.39 ns | [-] -324.6% | 934575 B | 2388 B |
| ComplexQuery | 370,601.03 ns | 318,673.03 ns | [+] +14.0% | 45395 B | 27185 B |
| Delete | 1,130,558.53 ns | 877,918.78 ns | [+] +22.3% | 112389 B | 5408 B |
| GetByCategory | 362,664.86 ns | 303,292.49 ns | [+] +16.4% | 47273 B | 38041 B |
| GetById | 30.43 ns | 139,731.26 ns | [-] -459089.2% | 56 B | 4512 B |
| GetTop100 | 461,512.61 ns | 333,233.61 ns | [+] +27.8% | 57755 B | 32665 B |
| Insert | 465,096.04 ns | 263,417.67 ns | [+] +43.4% | 100493 B | 3120 B |
| Update | 584,142.61 ns | 210,775.67 ns | [+] +63.9% | 103901 B | 2424 B |
SQLite (EF Core 10 vs Dapper Parameterized SQL)
| Operation | EF Core 10 Mean | SP/Dapper Mean | SP Advantage | EF Allocated | SP Allocated |
|---|---|---|---|---|---|
| BulkInsert | 3,983,762.42 ns | 1,433,281.07 ns | [+] +64.0% | 1069191 B | 224624 B |
| ComplexQuery | 227,635.31 ns | 219,356.47 ns | +3.6% | 60291 B | 37280 B |
| Delete | 1,853,441.66 ns | 1,568,872.74 ns | [+] +15.4% | 85874 B | 4600 B |
| GetByCategory | 163,085.39 ns | 155,062.37 ns | +4.9% | 54976 B | 40440 B |
| GetById | 25.58 ns | 12,820.59 ns | [-] -50019.6% | 56 B | 2440 B |
| GetTop100 | 219,662.66 ns | 116,373.96 ns | [+] +47.0% | 55137 B | 34024 B |
| Insert | 1,001,068.78 ns | 795,783.37 ns | [+] +20.5% | 71091 B | 2656 B |
| Update | 981,651.33 ns | 9,193.06 ns | [+] +99.1% | 78626 B | 1896 B |
- EF Core Dominates Simple Lookups
The biggest surprise was GetById.
EF Core executed this in ~30 ns, while the stored procedure approach took significantly longer.
This suggests EF Core benefits heavily from internal optimizations like caching and tracking for simple queries.
π Takeaway: For simple reads, EF Core is not just convenient, it can actually be faster.
- Stored Procedures Win on Writes
For Insert, Update, and Delete operations, stored procedures consistently outperformed EF Core:
Insert: ~43% faster
Update: ~64% faster
Delete: ~22% faster
π Why this happens:
EF Core adds change tracking overhead
SQL paths are more direct and optimized
π Takeaway: If your system is write-heavy, raw SQL still gives you better performance.
- Complex Queries Are Competitive
For more advanced queries, the difference becomes smaller:
ComplexQuery: ~14% advantage for stored procedures
GetByCategory: ~16% advantage
GetTop100: ~28% advantage
π Takeaway: EF Core is closing the gap. For many applications, the difference may not justify the added complexity of stored procedures.
- Bulk Insert Was Unexpected
EF Core actually performed better in bulk insert scenarios in this setup.
Thatβs not always the case, and it depends heavily on configuration and provider.
π Takeaway: Never assume. Always measure.
- Memory Usage
EF Core consistently allocated more memory compared to stored procedures.
Thatβs expected due to:
Change tracking
Object materialization
LINQ processing
π Takeaway: If memory pressure is a concern, this becomes an important factor.
Results: SQLite (EF Core vs Dapper)
Switching to SQLite gave a slightly different picture.
- Dapper Wins Most Operations
In SQLite tests, Dapper outperformed EF Core in:
Bulk Insert (~64% faster)
Update (~99% faster, very large gap)
GetTop100 (~47% faster)
Insert (~20% faster)
π Takeaway: For lightweight databases like SQLite, Dapper shines.
- EF Core Still Strong in Simple Reads
Again, GetById stands out.
EF Core performed extremely fast compared to Dapper.
π Takeaway: EF Core optimizations for simple queries are consistent across providers.
- Small Gaps in Some Queries
For operations like:
ComplexQuery (~3.6% difference)
GetByCategory (~4.9% difference)
The performance gap is minimal.
π Takeaway: In many real-world scenarios, you wonβt feel this difference.
Key Insights
Letβs simplify everything:
Where EF Core 10 Performs Well
Simple queries (especially GetById)
Read-heavy applications
Scenarios where developer productivity matters
Where Raw SQL / Dapper Still Wins
Heavy write operations
Bulk data processing
Performance-critical paths
What Improved in .NET 10
EF Core is clearly getting faster and more competitive.
No comments yet. Be the first to share your thoughts!