Skip to content

Commit 988c7e9

Browse files
fix: remove redundant option + refactor benchmark
1 parent 1640852 commit 988c7e9

63 files changed

Lines changed: 255 additions & 248 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,3 @@
1-
public static class ReadBenchmarkConsts
2-
{
3-
public const int CustomerCount = 500;
4-
public const int QueriesToRun = 1000;
5-
}
6-
71
public static class WriteBenchmarkConsts
82
{
9-
public const int TotalRecords = 2000000;
103
}

benchmark/BenchmarkRunner/Benchmarks/MysqlReadBenchmark.cs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,12 @@ namespace BenchmarkRunner.Benchmarks;
1212
[MarkdownExporterAttribute.GitHub]
1313
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1414
[CategoriesColumn]
15-
public class MysqlReadBenchmark
15+
public class MysqlReadBenchmark : ReadBenchmark
1616
{
1717
private static readonly string _connectionString = Config.GetMysqlConnectionString();
1818
private readonly QuerySql _sqlcImpl = new(_connectionString);
19-
private static bool _isInitialized = false;
20-
private static readonly SemaphoreSlim _initLock = new(1, 1);
2119

22-
[Params(ReadBenchmarkConsts.CustomerCount)]
23-
public int CustomerCount { get; set; }
24-
25-
[Params(ReadBenchmarkConsts.QueriesToRun)]
26-
public int QueriesToRun { get; set; }
27-
28-
[Params(100, 1000)]
29-
public int Limit { get; set; }
30-
31-
[Params(10, 50)]
20+
[Params(25, 100)]
3221
public int ConcurrentQueries { get; set; }
3322

3423
[GlobalSetup]
@@ -62,9 +51,9 @@ await seeder.SeedAsync(
6251

6352
[BenchmarkCategory("Read")]
6453
[Benchmark(Baseline = true, Description = "SQLC - GetCustomerOrders")]
65-
public async Task<List<QuerySql.GetCustomerOrdersRow>> Sqlc_GetCustomerOrders()
54+
public override async Task Sqlc_GetCustomerOrders()
6655
{
67-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
56+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
6857
{
6958
return _sqlcImpl.GetCustomerOrdersAsync(new QuerySql.GetCustomerOrdersArgs(
7059
CustomerId: Random.Shared.Next(1, CustomerCount),
@@ -76,9 +65,9 @@ await seeder.SeedAsync(
7665

7766
[BenchmarkCategory("Read")]
7867
[Benchmark(Description = "EFCore (NoTracking) - GetCustomerOrders")]
79-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_NoTracking_GetCustomerOrders()
68+
public override async Task EFCore_NoTracking_GetCustomerOrders()
8069
{
81-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
70+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
8271
{
8372
await using var dbContext = new SalesDbContext(_connectionString);
8473
var queries = new Queries(dbContext, useTracking: false);
@@ -92,9 +81,9 @@ await seeder.SeedAsync(
9281

9382
[BenchmarkCategory("Read")]
9483
[Benchmark(Description = "EFCore (WithTracking) - GetCustomerOrders")]
95-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_WithTracking_GetCustomerOrders()
84+
public override async Task EFCore_WithTracking_GetCustomerOrders()
9685
{
97-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
86+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
9887
{
9988
await using var dbContext = new SalesDbContext(_connectionString);
10089
var queries = new Queries(dbContext, useTracking: true);

benchmark/BenchmarkRunner/Benchmarks/MysqlWriteBenchmark.cs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,19 +13,18 @@ namespace BenchmarkRunner.Benchmarks;
1313
[MarkdownExporterAttribute.GitHub]
1414
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1515
[CategoriesColumn]
16-
public class MysqlWriteBenchmark
16+
public class MysqlWriteBenchmark : WriteBenchmark
1717
{
1818
private static readonly string _connectionString = Config.GetMysqlConnectionString();
1919
private readonly QuerySql _sqlcImpl = new(_connectionString);
2020
private readonly Queries _efCoreImpl = new(new SalesDbContext(_connectionString), useTracking: false);
2121
private List<QuerySql.AddOrderItemsArgs> _testOrderItems = null!;
22-
private static bool _isInitialized = false;
23-
private static readonly SemaphoreSlim _initLock = new(1, 1);
2422

25-
[Params(WriteBenchmarkConsts.TotalRecords)]
26-
public int TotalRecords { get; set; }
27-
28-
[Params(100, 500, 1000)]
23+
/// <summary>
24+
/// MySQL batch size can be very large yet very performant in SQLC implementation due to
25+
/// CSV load usage, so we wish to examine exceptionally large batches as well.
26+
/// </summary>
27+
[Params(200, 1000, 5000)]
2928
public int BatchSize { get; set; }
3029

3130
[GlobalSetup]
@@ -73,14 +72,14 @@ public void IterationSetup()
7372

7473
[BenchmarkCategory("Write")]
7574
[Benchmark(Baseline = true, Description = "SQLC - AddOrderItems")]
76-
public async Task Sqlc_AddOrderItems()
75+
public override async Task Sqlc_AddOrderItems()
7776
{
7877
await Helpers.InsertInBatchesAsync(_testOrderItems, BatchSize, _sqlcImpl.AddOrderItemsAsync);
7978
}
8079

8180
[BenchmarkCategory("Write")]
8281
[Benchmark(Description = "EFCore - AddOrderItems")]
83-
public async Task EFCore_AddOrderItems()
82+
public override async Task EFCore_AddOrderItems()
8483
{
8584
var args = _testOrderItems.Select(i => new Queries.AddOrderItemsArgs(
8685
i.OrderId, i.ProductId, i.Quantity, i.UnitPrice

benchmark/BenchmarkRunner/Benchmarks/PostgresqlReadBenchmark.cs

Lines changed: 8 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,12 @@ namespace BenchmarkRunner.Benchmarks;
1212
[MarkdownExporterAttribute.GitHub]
1313
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1414
[CategoriesColumn]
15-
public class PostgresqlReadBenchmark
15+
public class PostgresqlReadBenchmark : ReadBenchmark
1616
{
1717
private static readonly string _connectionString = Config.GetPostgresConnectionString();
1818
private readonly QuerySql _sqlcImpl = new(_connectionString);
19-
private static bool _isInitialized = false;
20-
private static readonly SemaphoreSlim _initLock = new(1, 1);
2119

22-
[Params(ReadBenchmarkConsts.CustomerCount)]
23-
public int CustomerCount { get; set; }
24-
25-
[Params(ReadBenchmarkConsts.QueriesToRun)]
26-
public int QueriesToRun { get; set; }
27-
28-
[Params(100, 1000)]
29-
public int Limit { get; set; }
30-
31-
[Params(10, 50)]
20+
[Params(25, 100)]
3221
public int ConcurrentQueries { get; set; }
3322

3423
[GlobalSetup]
@@ -64,9 +53,9 @@ await seeder.SeedAsync(
6453

6554
[BenchmarkCategory("Read")]
6655
[Benchmark(Baseline = true, Description = "SQLC - GetCustomerOrders")]
67-
public async Task<List<QuerySql.GetCustomerOrdersRow>> Sqlc_GetCustomerOrders()
56+
public override async Task Sqlc_GetCustomerOrders()
6857
{
69-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
58+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
7059
{
7160
return _sqlcImpl.GetCustomerOrdersAsync(new QuerySql.GetCustomerOrdersArgs(
7261
CustomerId: Random.Shared.Next(1, CustomerCount),
@@ -78,9 +67,9 @@ await seeder.SeedAsync(
7867

7968
[BenchmarkCategory("Read")]
8069
[Benchmark(Description = "EFCore (NoTracking) - GetCustomerOrders")]
81-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_NoTracking_GetCustomerOrders()
70+
public override async Task EFCore_NoTracking_GetCustomerOrders()
8271
{
83-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
72+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
8473
{
8574
await using var dbContext = new SalesDbContext(_connectionString);
8675
var queries = new Queries(dbContext, useTracking: false);
@@ -94,9 +83,9 @@ await seeder.SeedAsync(
9483

9584
[BenchmarkCategory("Read")]
9685
[Benchmark(Description = "EFCore (WithTracking) - GetCustomerOrders")]
97-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_WithTracking_GetCustomerOrders()
86+
public override async Task EFCore_WithTracking_GetCustomerOrders()
9887
{
99-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
88+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
10089
{
10190
await using var dbContext = new SalesDbContext(_connectionString);
10291
var queries = new Queries(dbContext, useTracking: true);

benchmark/BenchmarkRunner/Benchmarks/PostgresqlWriteBenchmark.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,19 +12,17 @@ namespace BenchmarkRunner.Benchmarks;
1212
[MarkdownExporterAttribute.GitHub]
1313
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1414
[CategoriesColumn]
15-
public class PostgresqlWriteBenchmark
15+
public class PostgresqlWriteBenchmark : WriteBenchmark
1616
{
1717
private static readonly string _connectionString = Config.GetPostgresConnectionString();
1818
private readonly QuerySql _sqlcImpl = new(_connectionString);
1919
private readonly Queries _efCoreImpl = new(new SalesDbContext(_connectionString), useTracking: false);
2020
private List<QuerySql.AddOrderItemsArgs> _testOrderItems = null!;
21-
private static bool _isInitialized = false;
22-
private static readonly SemaphoreSlim _initLock = new(1, 1);
2321

24-
[Params(WriteBenchmarkConsts.TotalRecords)]
25-
public int TotalRecords { get; set; }
26-
27-
[Params(100, 500, 1000)]
22+
/// <summary>
23+
/// PostgreSQL batch size can be larger in SQLC implementation due to using binary import.
24+
/// </summary>
25+
[Params(200, 500, 1000)]
2826
public int BatchSize { get; set; }
2927

3028
[GlobalSetup]
@@ -72,14 +70,14 @@ public void IterationSetup()
7270

7371
[BenchmarkCategory("Write")]
7472
[Benchmark(Baseline = true, Description = "SQLC - AddOrderItems")]
75-
public async Task Sqlc_AddOrderItems()
73+
public override async Task Sqlc_AddOrderItems()
7674
{
7775
await Helpers.InsertInBatchesAsync(_testOrderItems, BatchSize, _sqlcImpl.AddOrderItemsAsync);
7876
}
7977

8078
[BenchmarkCategory("Write")]
8179
[Benchmark(Description = "EFCore - AddOrderItems")]
82-
public async Task EFCore_AddOrderItems()
80+
public override async Task EFCore_AddOrderItems()
8381
{
8482
var args = _testOrderItems.Select(i => new Queries.AddOrderItemsArgs(
8583
i.OrderId, i.ProductId, i.Quantity, i.UnitPrice
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
public abstract class ReadBenchmark
4+
{
5+
protected bool _isInitialized = false;
6+
protected SemaphoreSlim _initLock = new(1, 1);
7+
8+
[Params(1000)]
9+
protected int QueriesToRun { get; set; }
10+
11+
[Params(500)]
12+
protected int CustomerCount { get; set; }
13+
14+
[Params(100, 500)]
15+
public int Limit { get; set; }
16+
17+
public abstract Task Sqlc_GetCustomerOrders();
18+
public abstract Task EFCore_NoTracking_GetCustomerOrders();
19+
public abstract Task EFCore_WithTracking_GetCustomerOrders();
20+
}

benchmark/BenchmarkRunner/Benchmarks/SqliteReadBenchmark.cs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,14 @@ namespace BenchmarkRunner.Benchmarks;
1212
[MarkdownExporterAttribute.GitHub]
1313
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1414
[CategoriesColumn]
15-
public class SqliteReadBenchmark
15+
public class SqliteReadBenchmark : ReadBenchmark
1616
{
1717
private static readonly string _connectionString = Config.GetSqliteConnectionString();
1818
private readonly QuerySql _sqlcImpl = new(_connectionString);
19-
private static bool _isInitialized = false;
20-
private static readonly SemaphoreSlim _initLock = new(1, 1);
21-
22-
[Params(ReadBenchmarkConsts.CustomerCount)]
23-
public int CustomerCount { get; set; }
24-
25-
[Params(ReadBenchmarkConsts.QueriesToRun)]
26-
public int QueriesToRun { get; set; }
27-
28-
[Params(50, 500)]
29-
public int Limit { get; set; }
3019

20+
/// <summary>
21+
/// SQLite supports read concurrency, but less so then other relational databases.
22+
/// </summary>
3123
[Params(5, 25)]
3224
public int ConcurrentQueries { get; set; }
3325

@@ -64,9 +56,9 @@ await seeder.SeedAsync(
6456

6557
[BenchmarkCategory("Read")]
6658
[Benchmark(Baseline = true, Description = "SQLC - GetCustomerOrders")]
67-
public async Task<List<QuerySql.GetCustomerOrdersRow>> Sqlc_GetCustomerOrders()
59+
public override async Task Sqlc_GetCustomerOrders()
6860
{
69-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
61+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, _ =>
7062
{
7163
return _sqlcImpl.GetCustomerOrdersAsync(new QuerySql.GetCustomerOrdersArgs(
7264
CustomerId: Random.Shared.Next(1, CustomerCount),
@@ -78,9 +70,9 @@ await seeder.SeedAsync(
7870

7971
[BenchmarkCategory("Read")]
8072
[Benchmark(Description = "EFCore (NoTracking) - GetCustomerOrders")]
81-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_NoTracking_GetCustomerOrders()
73+
public override async Task EFCore_NoTracking_GetCustomerOrders()
8274
{
83-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
75+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
8476
{
8577
await using var dbContext = new SalesDbContext(_connectionString);
8678
var queries = new Queries(dbContext, useTracking: false);
@@ -94,9 +86,9 @@ await seeder.SeedAsync(
9486

9587
[BenchmarkCategory("Read")]
9688
[Benchmark(Description = "EFCore (WithTracking) - GetCustomerOrders")]
97-
public async Task<List<Queries.GetCustomerOrdersRow>> EFCore_WithTracking_GetCustomerOrders()
89+
public override async Task EFCore_WithTracking_GetCustomerOrders()
9890
{
99-
return await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
91+
await Helpers.ExecuteConcurrentlyAsync(QueriesToRun, ConcurrentQueries, async _ =>
10092
{
10193
await using var dbContext = new SalesDbContext(_connectionString);
10294
var queries = new Queries(dbContext, useTracking: true);

benchmark/BenchmarkRunner/Benchmarks/SqliteWriteBenchmark.cs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,18 @@ namespace BenchmarkRunner.Benchmarks;
1212
[MarkdownExporterAttribute.GitHub]
1313
[GroupBenchmarksBy(BenchmarkLogicalGroupRule.ByCategory)]
1414
[CategoriesColumn]
15-
public class SqliteWriteBenchmark
15+
public class SqliteWriteBenchmark : WriteBenchmark
1616
{
1717
private static readonly string _connectionString = Config.GetSqliteConnectionString();
1818
private readonly QuerySql _sqlcImpl = new(_connectionString);
1919
private readonly Queries _efCoreImpl = new(new SalesDbContext(_connectionString), useTracking: false);
2020
private List<QuerySql.AddOrderItemsArgs> _testOrderItems = null!;
21-
private static bool _isInitialized = false;
22-
private static readonly SemaphoreSlim _initLock = new(1, 1);
23-
24-
[Params(WriteBenchmarkConsts.TotalRecords)]
25-
public int TotalRecords { get; set; }
2621

22+
/// <summary>
23+
/// SQLite batch size for SQLC can be large but due to the plugin implementation of batch inserts
24+
/// for SQLite, there is a limitation of 1000 bind variables in the resulting SQL.
25+
/// e.g. If we insert to a table with 10 columns, the maximum batch size is 1000 / 10 = 100.
26+
/// </summary>
2727
[Params(50, 100, 200)]
2828
public int BatchSize { get; set; }
2929

@@ -73,14 +73,14 @@ public void IterationSetup()
7373

7474
[BenchmarkCategory("Write")]
7575
[Benchmark(Baseline = true, Description = "SQLC - AddOrderItems")]
76-
public async Task Sqlc_AddOrderItems()
76+
public override async Task Sqlc_AddOrderItems()
7777
{
7878
await Helpers.InsertInBatchesAsync(_testOrderItems, BatchSize, _sqlcImpl.AddOrderItemsAsync);
7979
}
8080

8181
[BenchmarkCategory("Write")]
8282
[Benchmark(Description = "EFCore - AddOrderItems")]
83-
public async Task EFCore_AddOrderItems()
83+
public override async Task EFCore_AddOrderItems()
8484
{
8585
var args = _testOrderItems.Select(i => new Queries.AddOrderItemsArgs(
8686
i.OrderId, i.ProductId, i.Quantity, i.UnitPrice
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
using BenchmarkDotNet.Attributes;
2+
3+
public abstract class WriteBenchmark
4+
{
5+
protected bool _isInitialized = false;
6+
protected SemaphoreSlim _initLock = new(1, 1);
7+
8+
[Params(2000000)]
9+
protected int TotalRecords { get; set; }
10+
11+
public abstract Task Sqlc_AddOrderItems();
12+
public abstract Task EFCore_AddOrderItems();
13+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
public interface IBenchmarkRunner
2+
{
3+
Task RunReadsAsync();
4+
Task RunWritesAsync();
5+
}

0 commit comments

Comments
 (0)