Perfomance Benchmarks

Configuration

Benchmark Project Source Code
        
Norm 5.4.0.0
Dapper 2.0.0.0
EntityFrameworkCore 8.0.0.0
BenchmarkDotNet 0.13.10, 
.NET 8.0.0 (8.0.23.53103)
Debian GNU/Linux 12 (bookworm) (container)
Intel Xeon Processor (Skylake, IBRS), 1 CPU, 2 logical and 2 physical cores
    

Mapping class

Source
namespace NormBenchmarks;
public class PocoClass
{
    public int Id1 { get; set; }
    public string? Foo1 { get; set; }
    public string? Bar1 { get; set; }
    public DateTime DateTime1 { get; set; }
    public int Id2 { get; set; }
    public string? Foo2 { get; set; }
    public string? Bar2 { get; set; }
    public DateTime DateTime2 { get; set; }
    public string? LongFooBar { get; set; }
    public bool IsFooBar { get; set; }
}
namespace NormBenchmarks;
public class PocoClass
{
    public int Id1 { get; set; }
    public string? Foo1 { get; set; }
    public string? Bar1 { get; set; }
    public DateTime DateTime1 { get; set; }
    public int Id2 { get; set; }
    public string? Foo2 { get; set; }
    public string? Bar2 { get; set; }
    public DateTime DateTime2 { get; set; }
    public string? LongFooBar { get; set; }
    public bool IsFooBar { get; set; }
}

Benchmark Methods

ADO.NET Raw Command Reader Method

Source
using Npgsql;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Command_Reader()
    {
        if (connection.State != System.Data.ConnectionState.Open)
        {
            connection.Open();
        }
        using var command = new NpgsqlCommand(query, connection);
        using var reader = command.ExecuteReader();
        while (reader.Read())
        {
            var i = new PocoClass
            {
                Id1 = reader.GetInt32(0),
                Foo1 = reader.GetString(1),
                Bar1 = reader.GetString(2),
                DateTime1 = reader.GetDateTime(3),
                Id2 = reader.GetInt32(4),
                Foo2 = reader.GetString(5),
                Bar2 = reader.GetString(6),
                DateTime2 = reader.GetDateTime(7),
                LongFooBar = reader.GetString(8),
                IsFooBar = reader.GetBoolean(9),
            };

            var c = i;
        }
    }
}
using Npgsql;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Command_Reader()
    {
        if (connection.State != System.Data.ConnectionState.Open)
        {
            connection.Open();
        }
        using var command = new NpgsqlCommand(query, connection);
        using var reader = command.ExecuteReader();
        while (reader.Read())
        {
            var i = new PocoClass
            {
                Id1 = reader.GetInt32(0),
                Foo1 = reader.GetString(1),
                Bar1 = reader.GetString(2),
                DateTime1 = reader.GetDateTime(3),
                Id2 = reader.GetInt32(4),
                Foo2 = reader.GetString(5),
                Bar2 = reader.GetString(6),
                DateTime2 = reader.GetDateTime(7),
                LongFooBar = reader.GetString(8),
                IsFooBar = reader.GetBoolean(9),
            };

            var c = i;
        }
    }
}

Dapper Method (Buffered)

Source
using Dapper;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark(Baseline = true)]
    public void Dapper()
    {
        foreach (var i in connection.Query<PocoClass>(query))
        {
            var c = i;
        }
    }
}
using Dapper;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark(Baseline = true)]
    public void Dapper()
    {
        foreach (var i in connection.Query<PocoClass>(query))
        {
            var c = i;
        }
    }
}

Dapper Unbuffered Method

Source
using Dapper;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Dapper_Buffered_False()
    {
        foreach (var i in connection.Query<PocoClass>(query, buffered: false))
        {
            var c = i;
        }
    }
}
using Dapper;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Dapper_Buffered_False()
    {
        foreach (var i in connection.Query<PocoClass>(query, buffered: false))
        {
            var c = i;
        }
    }
}

EntityFrameworkCore 8 SqlQueryRaw Method

Source
using Microsoft.EntityFrameworkCore;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void EntityFrameworkCore_SqlQueryRaw()
    {
        foreach (var i in dbcontext.Database.SqlQueryRaw<PocoClass>(query))
        {
            var c = i;
        }
    }
}
using Microsoft.EntityFrameworkCore;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void EntityFrameworkCore_SqlQueryRaw()
    {
        foreach (var i in dbcontext.Database.SqlQueryRaw<PocoClass>(query))
        {
            var c = i;
        }
    }
}

Norm Instances Method

Source
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_PocoClass_Instances()
    {
        foreach (var i in connection.Read<PocoClass>(query))
        {
            var c = i;
        }
    }
}
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_PocoClass_Instances()
    {
        foreach (var i in connection.Read<PocoClass>(query))
        {
            var c = i;
        }
    }
}

Norm Anonymous Instances Method

Source
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Anonymous_Types()
    {
        foreach (var i in connection.Read(new
        {
            id1 = default(int),
            foo1 = default(string),
            bar1 = default(string),
            datetime1 = default(DateTime),
            id2 = default(int),
            foo2 = default(string),
            bar2 = default(string),
            datetime2 = default(DateTime),
            longFooBar = default(string),
            isFooBar = default(bool),
        },
        query))
        {
            var c = i;
        }
    }
}
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Anonymous_Types()
    {
        foreach (var i in connection.Read(new
        {
            id1 = default(int),
            foo1 = default(string),
            bar1 = default(string),
            datetime1 = default(DateTime),
            id2 = default(int),
            foo2 = default(string),
            bar2 = default(string),
            datetime2 = default(DateTime),
            longFooBar = default(string),
            isFooBar = default(bool),
        },
        query))
        {
            var c = i;
        }
    }
}

Norm Named Tuples Method

Source
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Named_Tuples()
    {
        foreach (var i in connection.Read<(
            int id1, 
            string foo1, 
            string bar1, 
            DateTime datetime1, 
            int id2, 
            string foo2, 
            string bar2, 
            DateTime datetime2, 
            string longFooBar, 
            bool isFooBar
        )>(query))
        {
            var c = i;
        }
    }
}
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Named_Tuples()
    {
        foreach (var i in connection.Read<(
            int id1, 
            string foo1, 
            string bar1, 
            DateTime datetime1, 
            int id2, 
            string foo2, 
            string bar2, 
            DateTime datetime2, 
            string longFooBar, 
            bool isFooBar
        )>(query))
        {
            var c = i;
        }
    }
}

Norm Tuples Method

Source
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Tuples()
    {
        foreach (var i in connection.Read<
            int, 
            string, 
            string, 
            DateTime, 
            int, 
            string, 
            string, 
            DateTime, 
            string, 
            bool>(query))
        {
            var c = i;
        }
    }
}
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_Tuples()
    {
        foreach (var i in connection.Read<
            int, 
            string, 
            string, 
            DateTime, 
            int, 
            string, 
            string, 
            DateTime, 
            string, 
            bool>(query))
        {
            var c = i;
        }
    }
}

Norm Name And Value Artray Method

Source
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_NameValue_Array()
    {
        foreach (var i in connection.Read(query))
        {
            var c = i;
        }
    }
}
using Norm;
namespace NormBenchmarks;
public partial class Benchmarks
{
    [BenchmarkDotNet.Attributes.Benchmark()]
    public void Norm_NameValue_Array()
    {
        foreach (var i in connection.Read(query))
        {
            var c = i;
        }
    }
}

Results

Runtime

Execution times (arithmetic mean in milliseconds) for 10, 1K, 10K and 100K iterations (lower is better).

Memory Consumption

Memory consumption (arithmetic mean in KB) for 10, 1K, 10K and 100K iterations (lower is better).

Raw Data

MethodRecordsMeanErrorStdDevMedianRatioRatioSDGen0Gen1Gen2AllocatedAlloc Ratio
Command_Reader10517.6 μs11.86 μs34.98 μs510.7 μs0.820.07---3.56 KB0.43
Dapper_Buffered_False10640.9 μs12.78 μs34.99 μs633.2 μs1.010.08---7.88 KB0.95
Dapper10634.3 μs12.64 μs31.94 μs632.4 μs1.000.000.9766--8.26 KB1.00
EntityFrameworkCore_SqlQueryRaw10731.3 μs17.24 μs49.73 μs726.5 μs1.150.091.9531--16.24 KB1.96
Norm_Anonymous_Types10549.6 μs11.12 μs32.27 μs545.3 μs0.870.060.9766--9.76 KB1.18
Norm_Named_Tuples_ReaderCallback10538.7 μs14.41 μs41.58 μs532.5 μs0.850.07---9.15 KB1.11
Norm_Named_Tuples10530.4 μs10.52 μs28.62 μs529.5 μs0.840.070.9766--9.15 KB1.11
Norm_NameValue_Array10535.1 μs14.10 μs41.13 μs524.2 μs0.840.070.9766--8.29 KB1.00
Norm_PocoClass_Instances_ReaderCallback10578.6 μs12.38 μs35.71 μs577.7 μs0.910.070.9766--10.29 KB1.25
Norm_PocoClass_Instances10569.9 μs13.84 μs40.16 μs562.9 μs0.900.07---9.58 KB1.16
Norm_Tuples_ReaderCallback10529.4 μs10.38 μs29.44 μs526.3 μs0.840.06---3.13 KB0.38
Norm_Tuples10544.7 μs15.78 μs46.54 μs534.2 μs0.860.08---2.9 KB0.35
Command_Reader1001,082.0 μs25.63 μs75.57 μs1,071.4 μs0.930.111.9531--27.57 KB0.38
Dapper_Buffered_False1001,183.8 μs27.81 μs80.67 μs1,181.4 μs1.010.117.8125--70.55 KB0.97
Dapper1001,181.3 μs40.83 μs119.11 μs1,155.6 μs1.000.007.8125--72.7 KB1.00
EntityFrameworkCore_SqlQueryRaw1001,264.0 μs33.98 μs99.65 μs1,254.3 μs1.080.143.9063--57.06 KB0.78
Norm_Anonymous_Types1001,187.9 μs29.33 μs86.49 μs1,177.7 μs1.020.127.8125--69.62 KB0.96
Norm_Named_Tuples_ReaderCallback1001,168.7 μs28.51 μs83.17 μs1,164.9 μs1.000.127.8125--75.31 KB1.04
Norm_Named_Tuples1001,141.8 μs29.73 μs87.66 μs1,127.3 μs0.980.127.8125--75.34 KB1.04
Norm_NameValue_Array1001,131.6 μs35.53 μs104.20 μs1,126.5 μs0.970.137.8125--67.46 KB0.93
Norm_PocoClass_Instances_ReaderCallback1001,172.5 μs30.57 μs90.13 μs1,162.5 μs1.000.127.8125--67.99 KB0.94
Norm_PocoClass_Instances1001,159.3 μs28.19 μs82.23 μs1,152.2 μs0.990.115.8594--60.29 KB0.83
Norm_Tuples_ReaderCallback1001,168.2 μs30.65 μs89.90 μs1,163.5 μs1.000.121.9531--21.49 KB0.30
Norm_Tuples1001,151.3 μs37.92 μs110.63 μs1,132.8 μs0.980.12---19.14 KB0.26
Command_Reader10005,213.1 μs117.43 μs342.54 μs5,182.4 μs0.920.0831.2500--295.41 KB0.40
Dapper_Buffered_False10005,652.6 μs130.18 μs383.83 μs5,651.8 μs1.000.0985.9375--724.73 KB0.98
Dapper10005,664.2 μs119.52 μs337.10 μs5,697.0 μs1.000.0085.937523.4375-740.91 KB1.00
EntityFrameworkCore_SqlQueryRaw10006,188.4 μs171.32 μs502.45 μs6,073.5 μs1.100.1146.8750--493.08 KB0.67
Norm_Anonymous_Types10006,178.6 μs128.68 μs377.40 μs6,138.1 μs1.100.1078.1250--695.44 KB0.94
Norm_Named_Tuples_ReaderCallback10005,745.9 μs124.33 μs360.70 μs5,762.3 μs1.020.0885.9375--764.51 KB1.03
Norm_Named_Tuples10005,805.5 μs136.91 μs403.68 μs5,810.5 μs1.030.0985.9375--764.46 KB1.03
Norm_NameValue_Array10005,441.5 μs119.22 μs351.53 μs5,460.1 μs0.970.0878.1250--686.66 KB0.93
Norm_PocoClass_Instances_ReaderCallback10005,903.2 μs137.69 μs403.82 μs5,878.9 μs1.040.0978.1250--672.88 KB0.91
Norm_PocoClass_Instances10005,768.0 μs131.37 μs387.34 μs5,758.0 μs1.020.0970.3125--594.89 KB0.80
Norm_Tuples_ReaderCallback10006,012.2 μs131.75 μs384.34 μs5,999.7 μs1.060.1023.4375--232.6 KB0.31
Norm_Tuples10006,068.6 μs131.16 μs384.66 μs6,085.6 μs1.070.0923.4375--209.06 KB0.28
Command_Reader1000039,086.7 μs843.15 μs2,472.83 μs38,714.8 μs0.650.06307.6923--2968.31 KB0.39
Dapper_Buffered_False1000043,874.3 μs874.83 μs2,304.65 μs43,873.8 μs0.730.06818.1818--7264.21 KB0.97
Dapper1000060,626.5 μs1,204.16 μs3,416.01 μs60,509.7 μs1.000.00888.8889555.5556222.22227521.52 KB1.00
EntityFrameworkCore_SqlQueryRaw1000049,088.0 μs976.52 μs2,754.30 μs48,755.4 μs0.810.06571.4286--4854 KB0.65
Norm_Anonymous_Types1000049,914.9 μs996.89 μs2,892.15 μs49,842.3 μs0.830.06777.7778--6953.85 KB0.92
Norm_Named_Tuples_ReaderCallback1000045,222.7 μs913.07 μs2,663.46 μs44,800.9 μs0.750.06909.0909--7655.62 KB1.02
Norm_Named_Tuples1000045,584.7 μs971.98 μs2,850.66 μs45,002.8 μs0.750.07909.0909--7655.89 KB1.02
Norm_NameValue_Array1000041,510.4 μs826.64 μs2,089.02 μs41,186.1 μs0.690.06833.3333--6875.11 KB0.91
Norm_PocoClass_Instances_ReaderCallback1000046,989.1 μs1,060.14 μs3,075.66 μs46,498.9 μs0.780.07818.1818--6722.9 KB0.89
Norm_PocoClass_Instances1000046,987.1 μs1,321.93 μs3,856.12 μs46,315.5 μs0.780.08500.0000--5941.23 KB0.79
Norm_Tuples_ReaderCallback1000047,840.8 μs955.95 μs2,696.26 μs47,634.9 μs0.790.06272.7273--2342.78 KB0.31
Norm_Tuples1000048,000.4 μs959.40 μs2,406.96 μs47,712.6 μs0.800.06181.8182--2108.96 KB0.28
Command_Reader100000360,967.3 μs13,542.97 μs39,931.76 μs360,128.5 μs0.620.083000.0000--30390.18 KB0.40
Dapper_Buffered_False100000408,091.0 μs11,757.30 μs34,482.13 μs407,562.3 μs0.690.078000.0000--73358.65 KB0.97
Dapper100000591,684.0 μs11,703.89 μs28,488.89 μs592,490.3 μs1.000.0010000.00005000.00002000.000075439.47 KB1.00
EntityFrameworkCore_SqlQueryRaw100000430,804.8 μs12,971.44 μs37,838.31 μs425,081.4 μs0.730.076000.0000--49150.92 KB0.65
Norm_Anonymous_Types100000409,893.5 μs11,396.52 μs32,881.55 μs408,157.2 μs0.690.068000.0000--70242.37 KB0.93
Norm_Named_Tuples_ReaderCallback100000437,003.3 μs14,050.01 μs41,426.78 μs431,296.2 μs0.740.089000.0000--77272.29 KB1.02
Norm_Named_Tuples100000421,935.6 μs13,088.49 μs37,553.34 μs418,119.5 μs0.710.089000.0000--77267.79 KB1.02
Norm_NameValue_Array100000402,777.6 μs11,877.34 μs34,458.32 μs403,955.8 μs0.680.078000.0000--69454.65 KB0.92
Norm_PocoClass_Instances_ReaderCallback100000446,899.3 μs13,511.26 μs39,838.24 μs445,233.2 μs0.760.088000.0000--67937.85 KB0.90
Norm_PocoClass_Instances100000399,019.8 μs10,339.23 μs29,995.97 μs392,905.9 μs0.680.067000.0000--60101.44 KB0.80
Norm_Tuples_ReaderCallback100000410,133.2 μs11,173.29 μs32,237.51 μs404,015.3 μs0.700.072000.0000--24142.09 KB0.32
Norm_Tuples100000407,943.4 μs12,391.90 μs35,753.46 μs410,471.0 μs0.690.072000.0000--21809.59 KB0.29
Comments