.NET SearchValues: When it actually boosts performance

Morgan42 Novice 1h ago Updated Jul 26, 2026 589 views 0 likes 2 min read

SearchValues<T> is often framed as a magic bullet for string scanning, but my recent benchmarks on a log parser show that the performance gains are highly situational. I decided to measure the actual impact on a 32MB buffer using .NET 10 in a Linux container to see where the overhead actually sits.

The Performance Gap

SearchValues (introduced in .NET 8) creates a precomputed set of values to optimize scanning. In theory, it's faster than IndexOfAny. In practice, the results depend on match density.

When delimiters are dense (one every ~60 characters), the difference is negligible:

IndexOfAny(char[]) : 10.2 ms
SearchValues       : 9.7 ms

However, when searching for rare characters (one every ~40 KB), the vectorized fast path actually has room to run:

IndexOfAny(char[]) : 5.6 ms
SearchValues       : 3.3 ms

That's a 1.7x speedup. The real takeaway here isn't that SearchValues is always better, but that hand-rolled foreach loops are the actual bottleneck. A manual loop checking characters was consistently 2x slower than both API options.

The Static Cache Requirement

The biggest "gotcha" is the instantiation cost. SearchValues is designed to be created once and reused. If you call .Create() inside a hot method, you're destroying your performance.

In a test with one million short lines:

  • Static SearchValues: 25.1 ms
  • Per-call SearchValues: 70.2 ms

If it isn't stored in a static readonly field, you're essentially adding overhead for no reason.

// Correct: Pay the setup cost once
static readonly SearchValues<char> Delimiters = SearchValues.Create(['=', '&', ';', '?', '#']);

// Incorrect: Avoid doing this in a loop/hot path
var delimiters = SearchValues.Create(['=', '&', ';', '?', '#']);

Practical Implementation Advice

If you're looking for a deep dive into optimizing your AI workflow or data processing pipeline in .NET, follow these rules for scanning:

1. Rare matches + Large buffers: Use SearchValues<T> stored in a static field.
2. Dense matches or short strings: Standard IndexOfAny is usually sufficient.
3. Manual loops: Replace them immediately. Whether you use SearchValues or IndexOfAny, the built-in APIs crush manual character checks.

For those needing multi-substring searches, .NET 9 added support for that, which is a separate beast entirely.

Full runnable sample:

https://github.com/ssukhpinder/dev-to-code-samples/tree/main
programmingAI ProgrammingAI Codingdotnetcsharp

All Replies (3)

C
CameronOwl Expert 9h ago
Just stick to Span. Tried this in a high-load project and the overhead wasn't worth the fuss.
0 Reply
S
SoloSmith Expert 9h ago
Found it helpful for filtering out common delimiters in some CSV parsing logic I wrote.
0 Reply
R
Riley97 Advanced 9h ago
saw similar results with my telemetry tool, depends a lot on the set size.
0 Reply

Write a Reply

Markdown supported