Amazon DynamoDB

Benchmarks

How ARX compares with other ways of doing the same work on Amazon DynamoDB, measured with BenchmarkDotNet.

ARX.SDK's DynamoDB provider against the hand-written low-level client code a developer would write (PutItemRequest, QueryRequest, TransactWriteItemsRequest: the baseline) and the AWS SDK's object persistence model (DynamoDBContext). BenchmarkDotNet, Release, on the arx-dynamodb container (DynamoDB Local 2.5.2, Docker Desktop on Windows), tables arx_bench_product, arx_bench_crm (with GSI1) and arx_bench_events (write-sharded 4 ways). Reports in results/. Ratios are against the raw client; numbers from one machine, so read the ratios, not the times.

Operation ARX against the raw client Notes
Create, one item (a conditional put) 1.00× DynamoDBContext's save (no condition: it overwrites) 1.01×
CreateMultiple, 25 and 100 items, one TransactWriteItems 0.98×, 1.14× (spread ±0.13) BatchWriteItem (not atomic): 1.28× and 3.99×
UpdateMultiple, 1, 25 and 100 items, conditional updates in one transaction 0.97×, 0.97×, 1.01× –
Update through an index (25 orders found by status, then updated by key) 1.03× against a Query of GSI1 and a transaction of conditional updates
Delete, 1 item; DeleteMultiple, 25 and 100 0.95×, 1.00×, 1.07× before tuning 1.48×, 1.13×, 1.74×
Retrieve by key (GetItem) 1.16× (spread ±0.10) the same code read 0.90× to 1.39× in five runs; DynamoDBContext 1.01× to 1.48×
RetrieveMultiple, 100 and 1,000 items of one partition 1.01×, 1.18× the raw baseline only counts the items; DynamoDBContext, which builds objects, 0.94× and 1.16×
RetrieveMultiple through GSI1 (200 orders) 0.98× –
Scan of 1,000 items with a filter (AllowScan) 1.03× –
A write-sharded partition, 100 and 1,000 items over 4 shards, in order 1.10×, 1.12× against four parallel queries merged by hand; before tuning 2.26×, 1.88×
Create and Retrieve against the Document model (Table.PutItemAsync with the same condition, Table.GetItemAsync) 1.01×, 1.11× the Document model 1.05×, 1.15× (one run, 2026-11-09)
Retrieve by many keys, 25 and 100: ARX has no single call, so one RetrieveAsync per key in parallel 1.42×, 0.69× against BatchGetItem the raw client's parallel GetItem 1.88×, 0.56×; DynamoDBContext batch get 1.11×, 1.00×. On DynamoDB Local a BatchGetItem of 100 is slower than 100 parallel GetItems, which says nothing about AWS; allocations 8× to 10× (one request per key)
A move (AllowKeyChange): the consistent read, then a delete and a put in one transaction 1.14× against the same GetItem and TransactWriteItems by hand

What the numbers say: writes are level with the raw client, deletes since the tuning; reads cost the dictionary entity, level with the AWS SDK's own mapper. ARX allocates more: 1.1× to 1.5× the raw client on reads, 2× to 4× on writes of 25 to 100 items (each item's key, condition and description kept for the error a failed transaction reports). Single-item timings swing by ±25% between runs on this machine. DynamoDB Local is not DynamoDB: its transactions take 65 to 90 ms whatever their size, so absolute times say nothing about AWS.

Reports

Not measured yet

Against AWS itself, nothing: these numbers are DynamoDB Local's. A read by many keys in one call has no ARX API yet (a condition id In (…) gives no partition, ARX8001): the BatchGetBenchmarks row is what an application does today.

A caution about this machine: the client runs on Windows and reaches DynamoDB Local through Docker Desktop's port forwarding, which stalls requests of more than about 8 KB by ~50 ms. The small move transaction above takes 6 ms; the 65 to 90 ms quoted for larger transactions may be that stall rather than DynamoDB Local. Not re-measured from inside the Docker network yet.

The reports

BenchmarkDotNet's own output for the runs the summary cites, as committed: every number above comes from one of these.

CreateBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
'Raw client: PutItem with attribute_not_exists' 6.090 ms 2.278 ms 1.0116 ms 1.02 0.21 - 28.08 KB 1.00
'DynamoDBContext SaveAsync (no condition: overwrites)' 6.018 ms 1.729 ms 0.7678 ms 1.01 0.18 7.8125 41.55 KB 1.48
'ARX CreateAsync' 5.966 ms 1.326 ms 0.4728 ms 1.00 0.15 - 32.43 KB 1.15
CreateMultipleBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
'Raw client: TransactWriteItems of conditional puts' 25 71.90 ms 3.636 ms 1.615 ms 1.00 0.03 85.54 KB 1.00
'Raw client: BatchWriteItem (no conditions, not atomic)' 25 91.84 ms 20.504 ms 9.104 ms 1.28 0.12 79.52 KB 0.93
'ARX CreateMultipleAsync' 25 70.77 ms 3.454 ms 1.807 ms 0.98 0.03 194.92 KB 2.28
'Raw client: TransactWriteItems of conditional puts' 100 87.20 ms 9.789 ms 5.120 ms 1.00 0.08 263.24 KB 1.00
'Raw client: BatchWriteItem (no conditions, not atomic)' 100 346.88 ms 52.102 ms 27.251 ms 3.99 0.37 317.04 KB 1.20
'ARX CreateMultipleAsync' 100 98.85 ms 20.054 ms 10.488 ms 1.14 0.13 699.27 KB 2.66
UpdateMultipleBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
'Raw client: UpdateItem / TransactWriteItems of conditional updates' 1 5.982 ms 2.028 ms 1.0604 ms 1.03 0.24 27.02 KB 1.00
'ARX UpdateAsync / UpdateMultipleAsync' 1 5.670 ms 1.051 ms 0.5498 ms 0.97 0.18 32.45 KB 1.20
'Raw client: UpdateItem / TransactWriteItems of conditional updates' 25 75.251 ms 6.132 ms 3.2071 ms 1.00 0.06 52.07 KB 1.00
'ARX UpdateAsync / UpdateMultipleAsync' 25 72.985 ms 4.823 ms 2.5225 ms 0.97 0.05 155.74 KB 2.99
'Raw client: UpdateItem / TransactWriteItems of conditional updates' 100 89.421 ms 15.954 ms 8.3442 ms 1.01 0.13 128.29 KB 1.00
'ARX UpdateAsync / UpdateMultipleAsync' 100 89.976 ms 12.918 ms 6.7561 ms 1.01 0.12 541.55 KB 4.22
UpdateByIndexBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
'Raw client: Query GSI1, then TransactWriteItems of conditional updates' 81.13 ms 3.704 ms 1.644 ms 1.00 0.03 149 KB 1.00
'ARX UpdateAsync with Match = Columns("status")' 83.25 ms 3.178 ms 1.662 ms 1.03 0.03 324.51 KB 2.18
DeleteMultipleBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]          : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  SingleOperation : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=SingleOperation  InvocationCount=1  IterationCount=12  
LaunchCount=1  RunStrategy=Monitoring  UnrollFactor=1  
WarmupCount=1  

Method Rows Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
'Raw client: DeleteItem (ALL_OLD) / TransactWriteItems of conditional deletes' 1 8.520 ms 4.260 ms 3.326 ms 1.08 0.47 30.04 KB 1.00
'Raw client: BatchWriteItem deletes (not atomic, no count)' 1 7.505 ms 1.788 ms 1.396 ms 0.95 0.26 28.34 KB 0.94
'ARX DeleteAsync / DeleteMultipleAsync' 1 7.487 ms 1.327 ms 1.036 ms 0.95 0.24 31.95 KB 1.06
'Raw client: DeleteItem (ALL_OLD) / TransactWriteItems of conditional deletes' 25 78.003 ms 14.213 ms 11.096 ms 1.02 0.19 43.37 KB 1.00
'Raw client: BatchWriteItem deletes (not atomic, no count)' 25 87.019 ms 9.526 ms 7.437 ms 1.13 0.17 37.45 KB 0.86
'ARX DeleteAsync / DeleteMultipleAsync' 25 76.493 ms 8.238 ms 6.432 ms 1.00 0.15 90.8 KB 2.09
'Raw client: DeleteItem (ALL_OLD) / TransactWriteItems of conditional deletes' 100 91.716 ms 13.044 ms 10.184 ms 1.01 0.15 90.01 KB 1.00
'Raw client: BatchWriteItem deletes (not atomic, no count)' 100 364.180 ms 42.505 ms 33.185 ms 4.01 0.55 144.13 KB 1.60
'ARX DeleteAsync / DeleteMultipleAsync' 100 97.121 ms 17.458 ms 13.630 ms 1.07 0.18 275.07 KB 3.06
RetrieveBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
'Raw client: GetItem / Query pages' 1 1.484 ms 0.2529 ms 0.1323 ms 1.01 0.12 5.8594 - 28.68 KB 1.00
'DynamoDBContext LoadAsync / QueryAsync' 1 1.910 ms 0.2628 ms 0.1374 ms 1.30 0.14 3.9063 - 35.24 KB 1.23
'ARX RetrieveAsync / RetrieveMultipleAsync' 1 1.710 ms 0.0890 ms 0.0395 ms 1.16 0.10 3.9063 - 31.53 KB 1.10
'Raw client: GetItem / Query pages' 100 4.385 ms 0.5940 ms 0.3107 ms 1.00 0.10 54.6875 15.6250 283.04 KB 1.00
'DynamoDBContext LoadAsync / QueryAsync' 100 4.086 ms 0.7836 ms 0.4098 ms 0.94 0.11 78.1250 23.4375 415.75 KB 1.47
'ARX RetrieveAsync / RetrieveMultipleAsync' 100 4.429 ms 0.7136 ms 0.3732 ms 1.01 0.11 70.3125 23.4375 379.97 KB 1.34
'Raw client: GetItem / Query pages' 1000 22.038 ms 1.3404 ms 0.5952 ms 1.00 0.04 437.5000 343.7500 2584.03 KB 1.00
'DynamoDBContext LoadAsync / QueryAsync' 1000 25.530 ms 1.6240 ms 0.7210 ms 1.16 0.04 583.3333 500.0000 3848.85 KB 1.49
'ARX RetrieveAsync / RetrieveMultipleAsync' 1000 25.910 ms 3.1513 ms 1.6482 ms 1.18 0.08 538.4615 307.6923 3475.47 KB 1.34
IndexAndScanBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Categories Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
'Raw client: Query GSI1 pages (200 orders by status)' Index 7.058 ms 2.5842 ms 1.1474 ms 1.02 0.21 93.7500 46.8750 538.91 KB 1.00
'ARX RetrieveMultipleAsync through GSI1' Index 6.778 ms 0.9655 ms 0.4287 ms 0.98 0.14 140.6250 78.1250 835.88 KB 1.55
'Raw client: Scan pages with a filter (1,000 products, int_value >= 500)' Scan 18.226 ms 1.6797 ms 0.8785 ms 1.00 0.06 187.5000 156.2500 1248.34 KB 1.00
'ARX RetrieveMultipleAsync with AllowScan' Scan 18.660 ms 2.2010 ms 0.9772 ms 1.03 0.07 312.5000 187.5000 1880.14 KB 1.51
ShardedReadBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Rows Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
'Raw client: Query each shard in parallel, then merge by SK' 100 3.995 ms 0.5194 ms 0.1852 ms 1.00 0.06 54.6875 15.6250 272.23 KB 1.00
'ARX RetrieveMultipleAsync of the page (shards merged)' 100 4.382 ms 0.7215 ms 0.3204 ms 1.10 0.09 78.1250 23.4375 382.37 KB 1.40
'Raw client: Query each shard in parallel, then merge by SK' 1000 13.050 ms 1.0940 ms 0.5722 ms 1.00 0.06 281.2500 187.5000 1735.18 KB 1.00
'ARX RetrieveMultipleAsync of the page (shards merged)' 1000 14.644 ms 2.2851 ms 1.1951 ms 1.12 0.10 437.5000 406.2500 2710.37 KB 1.56
DocumentModelBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Categories Mean Error StdDev Ratio RatioSD Gen0 Allocated Alloc Ratio
'Raw client: PutItem with attribute_not_exists' Create 5.890 ms 0.7810 ms 0.4085 ms 1.00 0.09 - 28.27 KB 1.00
'Document model: Table.PutItemAsync with the same condition' Create 6.140 ms 1.2497 ms 0.5549 ms 1.05 0.11 - 34.81 KB 1.23
'ARX CreateAsync' Create 5.949 ms 1.3954 ms 0.6196 ms 1.01 0.12 - 32.54 KB 1.15
'Raw client: GetItem (consistent)' Retrieve 1.662 ms 0.5897 ms 0.3084 ms 1.03 0.24 5.8594 28.69 KB 1.00
'Document model: Table.GetItemAsync (consistent)' Retrieve 1.861 ms 0.1655 ms 0.0866 ms 1.15 0.19 3.9063 32.76 KB 1.14
'ARX RetrieveAsync' Retrieve 1.791 ms 0.4265 ms 0.2231 ms 1.11 0.22 5.8594 31.54 KB 1.10
BatchGetBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]   : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  Standard : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=Standard  IterationCount=8  LaunchCount=1  
WarmupCount=3  

Method Keys Mean Error StdDev Ratio RatioSD Gen0 Gen1 Allocated Alloc Ratio
'Raw client: BatchGetItem (consistent, UnprocessedKeys retried)' 25 8.151 ms 0.6995 ms 0.3659 ms 1.00 0.06 15.6250 - 95.93 KB 1.00
'DynamoDBContext batch get (consistent)' 25 8.995 ms 1.6401 ms 0.8578 ms 1.11 0.11 31.2500 - 191.02 KB 1.99
'Raw client: one GetItem per key, in parallel' 25 15.284 ms 8.5942 ms 4.4950 ms 1.88 0.53 156.2500 31.2500 717.78 KB 7.48
'ARX: one RetrieveAsync per key, in parallel' 25 11.557 ms 2.8564 ms 1.4939 ms 1.42 0.18 156.2500 62.5000 785.81 KB 8.19
'Raw client: BatchGetItem (consistent, UnprocessedKeys retried)' 100 71.995 ms 13.7967 ms 7.2160 ms 1.01 0.15 - - 303.47 KB 1.00
'DynamoDBContext batch get (consistent)' 100 71.251 ms 6.2568 ms 3.2724 ms 1.00 0.12 142.8571 - 684.99 KB 2.26
'Raw client: one GetItem per key, in parallel' 100 39.684 ms 3.6582 ms 1.6243 ms 0.56 0.07 454.5455 363.6364 2870.47 KB 9.46
'ARX: one RetrieveAsync per key, in parallel' 100 49.407 ms 11.7926 ms 5.2360 ms 0.69 0.11 454.5455 363.6364 3146.82 KB 10.37
MoveBenchmarks

BenchmarkDotNet v0.15.8, Windows 11 (10.0.26200.9711/25H2/2025Update/HudsonValley2)
Intel Core i7-8750H CPU 2.20GHz (Max: 2.21GHz) (Coffee Lake), 1 CPU, 12 logical and 6 physical cores
.NET SDK 10.0.403
  [Host]          : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3
  SingleOperation : .NET 10.0.14 (10.0.14, 10.0.1426.52326), X64 RyuJIT x86-64-v3

Job=SingleOperation  InvocationCount=1  IterationCount=12  
LaunchCount=1  RunStrategy=Monitoring  UnrollFactor=1  
WarmupCount=1  

Method Mean Error StdDev Ratio RatioSD Allocated Alloc Ratio
'Raw client: GetItem, then TransactWriteItems (conditional delete + conditional put)' 5.714 ms 0.2964 ms 0.2314 ms 1.00 0.06 74.83 KB 1.00
'ARX UpdateAsync with AllowKeyChange' 6.511 ms 1.4933 ms 1.1658 ms 1.14 0.20 84.39 KB 1.13

Run them yourself

The benchmark code is published, so you can check these numbers on your own machine and database: arx-benchmark-dynamodb.zip. It builds against the ARX packages on nuget.org; HOW-TO-RUN.md inside says how to point it at a database and run it. Compare the ratios, not the absolute times.