Skip to content

Merlin Vs Dapper

Squil11ams edited this page Jul 16, 2026 · 4 revisions

Merlin vs Dapper Benchmark Results

Test Environment

  • Runtime: .NET 10.0.10
  • CPU: Intel Core i7-8086K @ 4.00GHz
  • OS: Windows 11
  • Dataset: 100,000 rows
  • Database: MySQL
  • Benchmark: BenchmarkDotNet
  • GC: Concurrent Workstation

Flat Object Mapping

Scenario: 100,000 User (11x Properties) records with no nested objects

Metric Dapper Merlin Difference
Mean Execution Time 349.5 ms 422.6 ms +73.1 ms
Relative Performance 1.00x 1.21x 21% slower
Allocated Memory 169.72 MB 190.32 MB +20.60 MB
Allocation Ratio 1.00x 1.12x 12% more
Gen0 Collections 29,000 34,000 +17%
Gen1 Collections 9,000 10,000 +11%
Gen2 Collections 2,000 3,000 +50%

Summary

Merlin introduced approximately:

  • 73 ms additional execution time
  • 20 MB additional allocations
  • ~21% execution overhead
  • ~12% allocation overhead

Nested Object Mapping

Scenario: 100,000 User (11 properties) records with one nested Client object (11 Properties)

Object structure:

Metric Dapper Merlin Difference
Mean Execution Time 726.6 ms 891.6 ms +165.0 ms
Relative Performance 1.00x 1.23x 23% slower
Allocated Memory 296.21 MB 323.68 MB +27.47 MB
Allocation Ratio 1.00x 1.09x 9% more
Gen0 Collections 50,000 56,000 +12%
Gen1 Collections 16,000 16,000 No difference
Gen2 Collections 1,000 3,000 +200%

Summary

Merlin introduced approximately:

  • 165 ms additional execution time
  • 27 MB additional allocations
  • ~23% execution overhead
  • ~9% allocation overhead

Dapper is faster, but not by much, the trade off is a simpler API

private static readonly QueryEngine DB = new("Local");

[Benchmark(Baseline = true)]
public int Test1_Dapper()
{
    using IDbConnection connection = new MySqlConnection(ConStr);

    string sql = "SELECT * FROM merlin_bench.users U LEFT JOIN merlin_bench.clients C ON U.user_client = C.client_id;";

    var result = connection.Query<UserExtended, Client, UserExtended>( sql, map: (user, profile) => {
            user.Client = profile;
            return user;
        },
        param: new { },
        splitOn: "client_id" // Tells Dapper where the Profile object fields begin
    );

    return result.AsList().Count();
}

[Benchmark]
public int Test2_Merlin()
{
    var q = new GenericQuery("SELECT * FROM merlin_bench.users U LEFT JOIN merlin_bench.clients C ON U.user_client = C.client_id;");

    var data = DB.GetList<UserExtended>(q);

    return data.Count;
}


Performance Analysis

Key Findings

Flat Object Mapping

Merlin performs approximately 21% slower than Dapper while allocating only 12% more memory.

The overhead is primarily associated with:

  • Metadata-driven mapping
  • Property lookup
  • Conversion handling
  • Automatic object hydration

Nested Object Mapping

With a nested object, Merlin maintains nearly the same performance ratio:

Test Merlin Overhead
Flat Object 21% slower
Nested Object 23% slower

This indicates that Merlin's object graph hydration does not introduce significant additional overhead as complexity increases.


Conclusion

The benchmark demonstrates that Merlin trades a small amount of runtime performance for increased mapping flexibility.

Dapper advantages:

  • Maximum raw performance
  • Minimal abstraction
  • Very efficient simple object mapping

Merlin advantages:

  • Automatic object hydration
  • Nested object support
  • Metadata-driven mapping
  • Reduced manual mapping code
  • Database abstraction without a full ORM tracking model

For business applications where maintainability and development speed are important, a ~20% performance

Clone this wiki locally