Skip to content

Performance: read paths fully deserialize all event payloads eagerly on every GetFrom* call #74

@AGiorgetti

Description

@AGiorgetti

Summary

Every GetFrom* read path calls doc.ToCommit(_serializer), which fully deserializes the entire commit and all event payloads — even when the caller only needs iteration or metadata.

What ToCommit does on every document

  • Deserializes the whole MongoCommit object from BsonDocument.
  • Iterates every stored event.
  • Deserializes each EventMessage payload.
  • Materializes the event set into an array.

Why this matters

  • Global checkpoint scans pay full payload materialization cost even when the caller only needs a cursor over commits.
  • This cost grows with event count and payload size.
  • Allocation pressure will likely dominate long sequential reads (especially for large event counts per commit).
  • This is the primary bottleneck for read-heavy workloads.

Baseline (net10, 2026-05-20)

Benchmark Mean
ReadFromEventStoreAsync(CommitsToWrite=10000) 120.443 ms
ReadFromStream(CommitsToWrite=10000) 148.004 ms

Proposed investigation

  • Benchmark small vs large payloads.
  • Benchmark 1 / 100 / 1000 events per commit to isolate per-event cost.
  • Compare global reads vs per-stream reads to isolate the effect.
  • Measure allocation pressure via BenchmarkDotNet MemoryDiagnoser.
  • Evaluate lazy/deferred deserialization for the global checkpoint scan path.

Reference

See docs/Performance-Investigation.md → Finding #2 for full context.

Metadata

Metadata

Assignees

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions