MicroORM
Documentation menu

Benchmarks

benchmarks/MicroORM.Benchmarks compares MicroORM with Dapper using BenchmarkDotNet. Both libraries run against the same in-memory SQLite database of 1,000 rows, with the same provider and connection handling: each operation opens a pooled connection, as both libraries do in typical use.

Results

BenchmarkDotNet ShortRun job, .NET 10.0.13, x64. Absolute times depend on the machine; the ratios are what matter.

ScenarioMeanRatio to DapperAllocated
Dapper: one row by id22.34 µs1.002.68 KB
MicroORM: one row by id, raw SQL21.89 µs0.983.87 KB
MicroORM: one row by id, Find24.29 µs1.096.47 KB
MicroORM: one row by id, typed Where26.02 µs1.167.47 KB
Dapper: 500 rows422.82 µs1.00295.64 KB
MicroORM: 500 rows423.67 µs1.00296.55 KB

What this shows:

  • Materialization is at parity. Reading 500 rows takes the same time and memory as Dapper.
  • Raw SQL is at parity. The interpolated-string API costs about 1 KB more per query than Dapper's anonymous-object parameters, with no measurable time difference.
  • Typed queries cost a few microseconds. Find and Where translate an expression into SQL on every call: about 2–4 µs and 4–5 KB more. That's small next to a real network round trip, but use raw SQL on the very hottest paths.

Findings that changed the code

The first run showed MicroORM allocating 12% more than Dapper for 500 rows: about 72 bytes per row. SQLite returns every integer as long, and converting it to an int or bool property through Convert.ChangeType boxed the result a second time. ValueConverter now has allocation-free fast paths for those widening conversions, which closed the gap entirely.

Typed column reads (GetInt32 and similar instead of GetValue) were considered and not adopted. With materialization already at parity, they would add complexity without a measurable gain. They would also be unsafe on SQLite, where a column's runtime type can vary from row to row.

Running the benchmarks

dotnet run -c Release --project benchmarks/MicroORM.Benchmarks -- --filter "*"
# Faster, less precise:
dotnet run -c Release --project benchmarks/MicroORM.Benchmarks -- --filter "*" --job short

Add a scenario by adding a [Benchmark] method to QueryBenchmarks. Keep the Dapper and MicroORM versions of a scenario identical apart from the library call.