Table of Contents

Performance

What was tested

Rinku was compared with Dapper using the same database, SQL, provider, and result shape. The tests include command execution, mapping, streaming, buffering, nullable and single-result semantics, scalar operations, procedures, parameters, and transactions.

The RinkuLib.Benchmarks project contains the benchmark definitions and setup.

Commands and mapping

These cases cover command setup, database-facing values, and the first step of turning rows into application shapes.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Executing a batch of commands 95,128.7 us
225.2 KB
Command: 90,293.9 us (0.95×)
163.99 KB (0.73×)
Mapping a complex result shape 546.9 us
15.63 KB
Command: 550.4 us (1.01×)
14.33 KB (0.92×)
SQL string: 539.3 us (0.99×)
14.33 KB (0.92×)
Managing the connection lifecycle asynchronously 742.6 us
23.09 KB
Command: 708.0 us (0.96×)
22.21 KB (0.96×)
SQL string: 716.8 us (0.97×)
22.21 KB (0.96×)
Mapping a custom database type asynchronously 691.1 us
19.5 KB
Command: 660.6 us (0.96×)
18.18 KB (0.93×)
Reading rows through a data reader asynchronously 632.7 us
12.13 KB
Command: 633.2 us (1.00×)
11.54 KB (0.95×)
Reading rows through a data reader synchronously 582.1 us
5.33 KB
Command: 586.2 us (1.01×)
4.73 KB (0.89×)
Mapping a dynamic result asynchronously 599.5 us
22.71 KB
Command: 610.8 us (1.02×)
21.46 KB (0.94×)
SQL string: 602.0 us (1.01×)
21.38 KB (0.94×)
Projecting a dynamic result asynchronously without details dynamic: 566.6 us
14.21 KB
raw dictionary: 567.7 us
13.44 KB
dynamic object: 559.3 us (0.99×)
12.14 KB (0.85×)
raw dictionary: 562.4 us (0.99×)
12.39 KB (0.87×)
Projecting a dynamic result asynchronously with details dynamic: 615.2 us
21.17 KB
raw dictionary: 600.2 us
20.17 KB
dynamic object: 591.9 us (0.96×)
18.59 KB (0.88×)
raw dictionary: 591.9 us (0.96×)
19.1 KB (0.90×)

Execution and parameters

These cases compare non-query work, scalar execution, SQL expansion, and parameter handling.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Executing a non-query asynchronously 1,494.1 us
10.99 KB
Command: 1,458.1 us (0.98×)
9.87 KB (0.90×)
SQL string: 1,466.3 us (0.98×)
9.87 KB (0.90×)
Executing a non-query synchronously 1,433.9 us
6.13 KB
Command: 1,415.4 us (0.99×)
5.02 KB (0.82×)
SQL string: 1,388.7 us (0.97×)
5.02 KB (0.82×)
Executing a scalar command asynchronously 1,335.0 us
13.52 KB
Command: 1,298.1 us (0.97×)
13.01 KB (0.96×)
SQL string: 1,304.2 us (0.98×)
13.01 KB (0.96×)
Passing explicit string metadata 567.7 us
13.75 KB
Command: 563.6 us (0.99×)
12.28 KB (0.89×)
Expanding an IN clause 753.9 us
51.74 KB
Command: 741.6 us (0.98×)
47.75 KB (0.92×)
SQL string: 749.3 us (0.99×)
47.75 KB (0.92×)
Replacing a literal in SQL 505.0 us
6.42 KB
numeric literal: 494.3 us (0.98×)
4.79 KB (0.75×)
parameterized count: 497.8 us (0.99×)
5.35 KB (0.83×)
Adding parameters manually 549.7 us
16.32 KB
Command: 537.9 us (0.98×)
14.7 KB (0.90×)
Reading multiple result sets asynchronously 647.1 us
33.59 KB
Command: 644.9 us (1.00×)
33.29 KB (0.99×)
SQL string: 641.9 us (0.99×)
33.29 KB (0.99×)
Reading multiple result sets synchronously 587.7 us
26.2 KB
Command: 586.5 us (1.00×)
24.79 KB (0.95×)
SQL string: 578.5 us (0.98×)
24.79 KB (0.95×)

Relationships and row mapping

These cases test nested and one-to-many shapes, separate result sets, and polymorphic row selection.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Folding joined rows into one-to-many objects 10,897.3 us
3379.17 KB
tuples: 10,572.4 us (0.97×)
2674.6 KB (0.79×)
native: 10,418.8 us (0.96×)
2205.87 KB (0.65×)
Mapping one-to-many data from separate result sets 11,127.2 us
2919 KB
Command: 9,375.4 us (0.84×)
2145.01 KB (0.73×)
Mapping ordered one-to-many data from separate result sets 8,452.4 us
2758.45 KB
Command: 7,811.2 us (0.92×)
1984.74 KB (0.72×)
Handling output and return parameters asynchronously 531.7 us
13.98 KB
Command: 527.7 us (0.99×)
12.57 KB (0.90×)
Selecting a parser for polymorphic rows 489.3 us
6.95 KB
row parser selection: 480.7 us (0.98×)
6.33 KB (0.91×)
interface factory: 481.0 us (0.98×)
6.33 KB (0.91×)

Streaming and buffering

These cases vary how results are consumed and how many rows are returned.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Streaming query results asynchronously (rowCount=50) 1,251.4 us
323.87 KB
Command: 1,243.2 us (0.99×)
316.7 KB (0.98×)
SQL string: 1,224.5 us (0.98×)
316.7 KB (0.98×)
Streaming query results asynchronously (rowCount=5000) 60,778.7 us
30488.39 KB
Command: 62,115.6 us (1.02×)
30132.88 KB (0.99×)
SQL string: 61,047.3 us (1.01×)
30132.8 KB (0.99×)
Buffering query results asynchronously (rowCount=50) 1,248.9 us
323.61 KB
Command: 1,258.9 us (1.01×)
317.71 KB (0.98×)
SQL string: 1,230.4 us (0.99×)
317.71 KB (0.98×)
Buffering query results asynchronously (rowCount=5000) 71,702.9 us
30623.25 KB
Command: 72,122.4 us (1.01×)
30270.99 KB (0.99×)
SQL string: 71,589.4 us (1.00×)
30269.54 KB (0.99×)
Buffering query results synchronously (rowCount=50) 1,192.6 us
316.97 KB
Command: 1,209.4 us (1.01×)
311 KB (0.98×)
SQL string: 1,193.3 us (1.00×)
311 KB (0.98×)
Buffering query results synchronously (rowCount=5000) 70,488.8 us
30613.8 KB
Command: 70,189.3 us (1.00×)
30261.7 KB (0.99×)
SQL string: 70,088.9 us (1.00×)
30261.88 KB (0.99×)
Streaming query results synchronously (rowCount=50) 1,192.3 us
315.85 KB
Command: 1,223.3 us (1.03×)
309.95 KB (0.98×)
SQL string: 1,207.3 us (1.01×)
309.95 KB (0.98×)
Streaming query results synchronously (rowCount=5000) 59,446.8 us
30480.28 KB
Command: 60,506.4 us (1.02×)
30126.01 KB (0.99×)
SQL string: 60,037.6 us (1.01×)
30126.01 KB (0.99×)

Result selection

These cases compare the semantics for nullable results, optional results, and single-result guarantees.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Querying a nullable reference with a default asynchronously 536.2 us
13.5 KB
Command: 549.6 us (1.03×)
12.24 KB (0.91×)
SQL string: 534.3 us (1.00×)
12.24 KB (0.91×)
Querying a nullable reference with a default synchronously 488.0 us
6.56 KB
Command: 495.8 us (1.02×)
5.45 KB (0.83×)
SQL string: 500.0 us (1.02×)
5.45 KB (0.83×)
Querying a nullable reference asynchronously 581.7 us
13.5 KB
Command: 528.9 us (0.91×)
12.24 KB (0.91×)
SQL string: 522.3 us (0.90×)
12.24 KB (0.91×)
Querying a nullable reference synchronously 502.5 us
6.56 KB
Command: 497.0 us (0.99×)
5.45 KB (0.83×)
SQL string: 504.9 us (1.01×)
5.45 KB (0.83×)
Querying a nullable value asynchronously 564.8 us
13.36 KB
Command: 561.3 us (0.99×)
12.07 KB (0.90×)
SQL string: 534.6 us (0.95×)
12.07 KB (0.90×)
Querying a nullable value synchronously 493.2 us
6.53 KB
Command: 491.6 us (1.00×)
5.39 KB (0.83×)
SQL string: 503.8 us (1.02×)
5.39 KB (0.83×)
Querying one result or a default asynchronously 606.5 us
22.65 KB
optional: 600.4 us (0.99×)
21.32 KB (0.94×)
optional nullable: 575.6 us (0.95×)
21.32 KB (0.94×)
optional: 583.0 us (0.96×)
21.32 KB (0.94×)
optional nullable: 584.0 us (0.96×)
21.32 KB (0.94×)
Querying one result or a default synchronously 552.8 us
15.87 KB
optional: 541.0 us (0.98×)
14.69 KB (0.93×)
optional nullable: 544.2 us (0.98×)
14.69 KB (0.93×)
optional: 541.8 us (0.98×)
14.69 KB (0.93×)
optional nullable: 555.6 us (1.01×)
14.69 KB (0.93×)
Querying one result, enforcing a single row, or a default asynchronously 771.7 us
22.88 KB
Command: 621.0 us (0.81×)
21.53 KB (0.94×)
SQL string: 588.4 us (0.77×)
21.46 KB (0.94×)
Querying one result, enforcing a single row, or a default synchronously 556.2 us
15.87 KB
Command: 540.4 us (0.97×)
14.69 KB (0.93×)
SQL string: 535.9 us (0.96×)
14.69 KB (0.93×)
Querying exactly one result asynchronously 594.5 us
22.79 KB
Command: 589.6 us (0.99×)
21.46 KB (0.94×)
SQL string: 596.6 us (1.00×)
21.46 KB (0.94×)
Querying exactly one result synchronously 553.5 us
15.87 KB
Command: 548.8 us (0.99×)
14.69 KB (0.93×)
SQL string: 538.9 us (0.97×)
14.69 KB (0.93×)
Querying one result asynchronously 600.9 us
22.65 KB
Command: 597.6 us (0.99×)
21.32 KB (0.94×)
SQL string: 600.4 us (1.00×)
21.32 KB (0.94×)
Querying one result synchronously 547.0 us
15.87 KB
Command: 540.5 us (0.99×)
14.69 KB (0.93×)
SQL string: 543.8 us (0.99×)
14.69 KB (0.93×)

Scalar and database operations

These cases cover scalar sequences, conditional counts, procedures, table-valued parameters, transactions, and execution context.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Reading a scalar sequence asynchronously 1,863.6 us
202.22 KB
Command: 1,818.9 us (0.98×)
84.01 KB (0.42×)
SQL string: 1,877.8 us (1.01×)
84.02 KB (0.42×)
Counting rows with a fixed and conditional path using a parameter 566.2 us
13.35 KB
fixed path: 565.8 us (1.00×)
11.91 KB (0.89×)
conditional path: 558.6 us (0.99×)
11.91 KB (0.89×)
Counting rows with a fixed and conditional path without a parameter 1,337.2 us
12.22 KB
fixed path: 1,307.0 us (0.98×)
10.85 KB (0.89×)
conditional path: 1,334.8 us (1.00×)
11.2 KB (0.92×)
Reading a scalar result asynchronously 1,321.8 us
12.22 KB
Command: 1,339.9 us (1.01×)
10.85 KB (0.89×)
SQL string: 1,356.2 us (1.03×)
10.85 KB (0.89×)
Calling a stored procedure asynchronously 589.5 us
21.9 KB
Command: 577.8 us (0.98×)
21.14 KB (0.97×)
Passing a table-valued parameter asynchronously 1,226.1 us
16.34 KB
Command: 1,223.0 us (1.00×)
14.84 KB (0.91×)
Applying timeout and cancellation context 1,255.8 us
324.21 KB
Command: 1,256.1 us (1.00×)
318.31 KB (0.98×)
Executing inside a transaction synchronously 1,473.8 us
6.61 KB
Command: 1,489.1 us (1.01×)
6.61 KB (1.00×)

Typed projection

These cases compare typed projection with and without additional details.

Test idea Dapper
Mean / Allocated
Rinku
Mean (Ratio) / Allocated (Alloc Ratio)
Projecting a typed result asynchronously without details 561.0 us
14.1 KB
Command: 564.2 us (1.01×)
12.16 KB (0.86×)
Projecting a typed result asynchronously with details 587.5 us
21.04 KB
Command: 572.8 us (0.98×)
18.59 KB (0.88×)