5 C# Secrets That Make LINQ Queries 10x Faster (You're Using It Wrong)
Cristian Sifuentes\
Senior .NET Engineer · 2026 Edition
TL;DR
LINQ is not slow. Your mental model of LINQ is.
The difference between expressive LINQ and optimized LINQ is
understanding:
- Enumeration cost
- Allocation pressure
- Short-circuiting semantics
- Projection order
- Materialization strategy
Secret 1 --- The Multi‑Enumeration Tax
var expensiveQuery = allUsers
.Where(u => u.IsActive)
.Select(u => new UserDto(u.Id, u.Name, u.CalculateScore()));
This query has NOT executed yet.
Now:
Console.WriteLine(expensiveQuery.Count());
var first = expensiveQuery.FirstOrDefault();
foreach (var user in expensiveQuery)
{
}
You just executed the same pipeline multiple times.
Fix
var cached = allUsers
.Where(u => u.IsActive)
.Select(u => new UserDto(u.Id, u.Name, u.CalculateScore()))
.ToList();
Enumerate once. Reuse many.
Secret 2 --- Allocation Awareness
LINQ creates enumerators. Enumerators usually allocate.
var result = numbers
.Where(n => n % 2 == 0)
.Take(10)
.ToList();
Hot path? Consider Span.
Span<int> span = numbers;
var results = new List<int>(10);
foreach (ref readonly var n in span)
{
if ((n & 1) == 0)
{
results.Add(n);
if (results.Count == 10)
break;
}
}
Zero iterator allocations. Predictable performance.
Secret 3 --- Filter Before Projection
Wrong:
var dtos = products
.Select(p => new ProductDto(p.Id, p.Price))
.Where(dto => dto.Price > 500)
.ToList();
Correct:
var dtos = products
.Where(p => p.Price > 500)
.Select(p => new ProductDto(p.Id, p.Price))
.ToList();
With EF Core this also reduces SQL payload.
Secret 4 --- Short‑Circuit Properly
Avoid:
var user = users.Where(u => u.Email == email)
.Take(1)
.FirstOrDefault();
Use:
var user = users.FirstOrDefault(u => u.Email == email);
Or:
bool exists = users.Any(u => u.Email == email);
Immediate exit. No wrapping.
Secret 5 --- Materialize Intentionally
Wrong:
var count = users.Where(u => u.IsActive).ToList().Count;
Correct:
var count = users.Count(u => u.IsActive);
Need array?
var arr = users.Where(u => u.IsActive).ToArray();
Need dictionary?
var lookup = users.Where(u => u.IsActive)
.ToDictionary(u => u.Id);
Pick the final structure directly.
Memory Model Matters
- IEnumerable
<T>{=html} → deferred, heap-driven iteration - IQueryable
<T>{=html} → expression tree translation - Span
<T>{=html} → stack-bound, ref-struct, zero alloc
Performance comes from mechanical sympathy.
Senior Rules
- Don't re-enumerate.
- Filter early.
- Project late.
- Short-circuit aggressively.
- Materialize with intent.
Cristian Sifuentes\
Performance-first .NET Engineer

Top comments (0)