Skip to content

Commit 23ee8c1

Browse files
author
fabien.menager
committed
Optimize benchmark run
1 parent 4c90ebd commit 23ee8c1

8 files changed

Lines changed: 78 additions & 117 deletions

File tree

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparator.RawInsert.cs

Lines changed: 56 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
using Microsoft.Data.Sqlite;
55
using Microsoft.EntityFrameworkCore;
66

7+
using MySqlConnector;
8+
79
using Npgsql;
810

911
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
@@ -25,7 +27,6 @@ private void RawInsertPostgreSql()
2527
"Identifier",
2628
"CreatedAt",
2729
"UpdatedAt",
28-
"StringEnumValue",
2930
"NumericEnumValue"
3031
) FROM STDIN (FORMAT BINARY)
3132
""";
@@ -39,7 +40,6 @@ private void RawInsertPostgreSql()
3940
writer.Write(entity.Identifier);
4041
writer.Write(entity.CreatedAt);
4142
writer.Write(entity.UpdatedAt);
42-
writer.Write(entity.StringEnumValue.ToString());
4343
writer.Write((int)entity.NumericEnumValue);
4444
}
4545

@@ -63,17 +63,15 @@ private void RawInsertSqlite()
6363
"Identifier",
6464
"CreatedAt",
6565
"UpdatedAt",
66-
"StringEnumValue",
6766
"NumericEnumValue"
68-
) VALUES (@Name, @Price, @Identifier, @CreatedAt, @UpdatedAt, @StringEnumValue, @NumericEnumValue)
67+
) VALUES (@Name, @Price, @Identifier, @CreatedAt, @UpdatedAt, @NumericEnumValue)
6968
""";
7069

7170
command.Parameters.Add(new SqliteParameter("@Name", DbType.String));
7271
command.Parameters.Add(new SqliteParameter("@Price", DbType.Decimal));
7372
command.Parameters.Add(new SqliteParameter("@Identifier", DbType.Guid));
7473
command.Parameters.Add(new SqliteParameter("@CreatedAt", DbType.DateTime));
7574
command.Parameters.Add(new SqliteParameter("@UpdatedAt", DbType.DateTime2));
76-
command.Parameters.Add(new SqliteParameter("@StringEnumValue", DbType.String));
7775
command.Parameters.Add(new SqliteParameter("@NumericEnumValue", DbType.Int32));
7876

7977
foreach (var entity in data)
@@ -83,7 +81,6 @@ private void RawInsertSqlite()
8381
command.Parameters["@Identifier"].Value = entity.Identifier;
8482
command.Parameters["@CreatedAt"].Value = entity.CreatedAt;
8583
command.Parameters["@UpdatedAt"].Value = entity.UpdatedAt;
86-
command.Parameters["@StringEnumValue"].Value = entity.StringEnumValue.ToString();
8784
command.Parameters["@NumericEnumValue"].Value = (int)entity.NumericEnumValue;
8885

8986
command.ExecuteNonQuery();
@@ -111,7 +108,6 @@ private void RawInsertSqlServer()
111108
bulkCopy.ColumnMappings.Add("Identifier", "Identifier");
112109
bulkCopy.ColumnMappings.Add("CreatedAt", "CreatedAt");
113110
bulkCopy.ColumnMappings.Add("UpdatedAt", "UpdatedAt");
114-
bulkCopy.ColumnMappings.Add("StringEnumValue", "StringEnumValue");
115111
bulkCopy.ColumnMappings.Add("NumericEnumValue", "NumericEnumValue");
116112

117113
var dataTable = new DataTable();
@@ -120,7 +116,6 @@ private void RawInsertSqlServer()
120116
dataTable.Columns.Add("Identifier", typeof(Guid));
121117
dataTable.Columns.Add("CreatedAt", typeof(DateTime));
122118
dataTable.Columns.Add("UpdatedAt", typeof(DateTimeOffset));
123-
dataTable.Columns.Add("StringEnumValue", typeof(string));
124119
dataTable.Columns.Add("NumericEnumValue", typeof(int));
125120

126121
foreach (var entity in data)
@@ -131,7 +126,59 @@ private void RawInsertSqlServer()
131126
row["Identifier"] = entity.Identifier;
132127
row["CreatedAt"] = entity.CreatedAt;
133128
row["UpdatedAt"] = entity.UpdatedAt;
134-
row["StringEnumValue"] = entity.StringEnumValue.ToString();
129+
row["NumericEnumValue"] = (int)entity.NumericEnumValue;
130+
dataTable.Rows.Add(row);
131+
132+
if (dataTable.Rows.Count >= 50_000)
133+
{
134+
bulkCopy.WriteToServer(dataTable);
135+
dataTable.Clear();
136+
}
137+
}
138+
139+
if (dataTable.Rows.Count > 0)
140+
{
141+
bulkCopy.WriteToServer(dataTable);
142+
}
143+
}
144+
145+
private void RawInsertMySql()
146+
{
147+
var connection = (MySqlConnection)DbContext.Database.GetDbConnection();
148+
if (connection.State != ConnectionState.Open)
149+
{
150+
connection.Open();
151+
}
152+
153+
var bulkCopy = new MySqlBulkCopy(connection);
154+
155+
bulkCopy.DestinationTableName = nameof(TestEntity);
156+
bulkCopy.BulkCopyTimeout = 60;
157+
158+
var i = 0;
159+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "Name"));
160+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "Price"));
161+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "Identifier"));
162+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "CreatedAt"));
163+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "UpdatedAt"));
164+
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(i++, "NumericEnumValue"));
165+
166+
var dataTable = new DataTable();
167+
dataTable.Columns.Add("Name", typeof(string));
168+
dataTable.Columns.Add("Price", typeof(decimal));
169+
dataTable.Columns.Add("Identifier", typeof(Guid));
170+
dataTable.Columns.Add("CreatedAt", typeof(DateTime));
171+
dataTable.Columns.Add("UpdatedAt", typeof(DateTimeOffset));
172+
dataTable.Columns.Add("NumericEnumValue", typeof(int));
173+
174+
foreach (var entity in data)
175+
{
176+
var row = dataTable.NewRow();
177+
row["Name"] = entity.Name;
178+
row["Price"] = entity.Price;
179+
row["Identifier"] = entity.Identifier;
180+
row["CreatedAt"] = entity.CreatedAt;
181+
row["UpdatedAt"] = entity.UpdatedAt;
135182
row["NumericEnumValue"] = (int)entity.NumericEnumValue;
136183
dataTable.Rows.Add(row);
137184

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparator.cs

Lines changed: 7 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,18 @@
11
using BenchmarkDotNet.Attributes;
2+
using BenchmarkDotNet.Engines;
23

34
using DotNet.Testcontainers.Containers;
45

56
using EFCore.BulkExtensions;
67

78
using LinqToDB.EntityFrameworkCore;
89

9-
using Microsoft.Data.SqlClient;
10-
using Microsoft.Data.Sqlite;
11-
using Microsoft.EntityFrameworkCore;
12-
13-
using MySqlConnector;
14-
15-
using Npgsql;
16-
1710
using PhenX.EntityFrameworkCore.BulkInsert.Extensions;
1811

1912
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
2013

14+
[MemoryDiagnoser]
15+
[SimpleJob(RunStrategy.ColdStart, launchCount: 1, warmupCount: 0, iterationCount: 5)]
2116
public abstract partial class LibComparator
2217
{
2318
[Params(500_000/*, 1_000_000/*, 10_000_000*/)]
@@ -34,7 +29,6 @@ public void IterationSetup()
3429
Name = $"Entity{i}",
3530
Price = (decimal)(i * 0.1),
3631
Identifier = Guid.NewGuid(),
37-
StringEnumValue = (StringEnum)(i % 2),
3832
NumericEnumValue = (NumericEnum)(i % 2),
3933
}).ToList();
4034

@@ -135,65 +129,10 @@ await DbContext.BulkInsertAsync(data, options =>
135129
// });
136130
// }
137131

138-
// [Benchmark]
139-
// public async Task EFCore_SaveChanges()
140-
// {
141-
// DbContext.AddRange(data);
142-
// await DbContext.SaveChangesAsync();
143-
// }
144-
145-
private void RawInsertMySql()
132+
[Benchmark]
133+
public async Task EFCore_SaveChanges()
146134
{
147-
var connection = (MySqlConnection)DbContext.Database.GetDbConnection();
148-
if (connection.State != ConnectionState.Open)
149-
{
150-
connection.Open();
151-
}
152-
153-
var bulkCopy = new MySqlBulkCopy(connection);
154-
155-
bulkCopy.DestinationTableName = nameof(TestEntity);
156-
bulkCopy.BulkCopyTimeout = 60;
157-
158-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(0, "Name"));
159-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(1, "Price"));
160-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(2, "Identifier"));
161-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(3, "CreatedAt"));
162-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(4, "UpdatedAt"));
163-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(5, "StringEnumValue"));
164-
bulkCopy.ColumnMappings.Add(new MySqlBulkCopyColumnMapping(6, "NumericEnumValue"));
165-
166-
var dataTable = new DataTable();
167-
dataTable.Columns.Add("Name", typeof(string));
168-
dataTable.Columns.Add("Price", typeof(decimal));
169-
dataTable.Columns.Add("Identifier", typeof(Guid));
170-
dataTable.Columns.Add("CreatedAt", typeof(DateTime));
171-
dataTable.Columns.Add("UpdatedAt", typeof(DateTimeOffset));
172-
dataTable.Columns.Add("StringEnumValue", typeof(string));
173-
dataTable.Columns.Add("NumericEnumValue", typeof(int));
174-
175-
foreach (var entity in data)
176-
{
177-
var row = dataTable.NewRow();
178-
row["Name"] = entity.Name;
179-
row["Price"] = entity.Price;
180-
row["Identifier"] = entity.Identifier;
181-
row["CreatedAt"] = entity.CreatedAt;
182-
row["UpdatedAt"] = entity.UpdatedAt;
183-
row["StringEnumValue"] = entity.StringEnumValue.ToString();
184-
row["NumericEnumValue"] = (int)entity.NumericEnumValue;
185-
dataTable.Rows.Add(row);
186-
187-
if (dataTable.Rows.Count >= 50_000)
188-
{
189-
bulkCopy.WriteToServer(dataTable);
190-
dataTable.Clear();
191-
}
192-
}
193-
194-
if (dataTable.Rows.Count > 0)
195-
{
196-
bulkCopy.WriteToServer(dataTable);
197-
}
135+
DbContext.AddRange(data);
136+
await DbContext.SaveChangesAsync();
198137
}
199138
}
Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
using BenchmarkDotNet.Configs;
22
using BenchmarkDotNet.Running;
33

4+
using PhenX.EntityFrameworkCore.BulkInsert.Benchmark.Providers;
5+
46
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
57

68
public class Program
@@ -11,9 +13,14 @@ public static void Main(string[] args)
1113
.Create(DefaultConfig.Instance)
1214
.WithOptions(ConfigOptions.DisableOptimizationsValidator);
1315

14-
BenchmarkRunner.Run<LibComparatorMySql>(config);
15-
BenchmarkRunner.Run<LibComparatorPostgreSql>(config);
16-
BenchmarkRunner.Run<LibComparatorSqlServer>(config);
17-
BenchmarkRunner.Run<LibComparatorSqlite>(config);
16+
var comparators = new[]
17+
{
18+
typeof(LibComparatorMySql),
19+
typeof(LibComparatorPostgreSql),
20+
typeof(LibComparatorSqlite),
21+
typeof(LibComparatorSqlServer),
22+
};
23+
24+
BenchmarkRunner.Run(comparators, config);
1825
}
1926
}

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparatorMySql.cs renamed to tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/Providers/LibComparatorMySql.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using BenchmarkDotNet.Attributes;
2-
using BenchmarkDotNet.Engines;
3-
41
using DotNet.Testcontainers.Containers;
52

63
using Microsoft.EntityFrameworkCore;
@@ -9,11 +6,8 @@
96

107
using Testcontainers.MySql;
118

12-
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
9+
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark.Providers;
1310

14-
[MinColumn, MaxColumn, BaselineColumn]
15-
[MemoryDiagnoser]
16-
[SimpleJob(RunStrategy.Throughput, launchCount: 1, warmupCount: 0, iterationCount: 5)]
1711
public class LibComparatorMySql : LibComparator
1812
{
1913
protected override void ConfigureDbContext()

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparatorPostgreSql.cs renamed to tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/Providers/LibComparatorPostgreSql.cs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using BenchmarkDotNet.Attributes;
2-
using BenchmarkDotNet.Engines;
3-
41
using DotNet.Testcontainers.Containers;
52

63
using LinqToDB.EntityFrameworkCore;
@@ -11,10 +8,8 @@
118

129
using Testcontainers.PostgreSql;
1310

14-
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
11+
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark.Providers;
1512

16-
[MemoryDiagnoser]
17-
[SimpleJob(RunStrategy.Throughput, launchCount: 1, warmupCount: 0, iterationCount: 5)]
1813
public class LibComparatorPostgreSql : LibComparator
1914
{
2015
protected override void ConfigureDbContext()

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparatorSqlServer.cs renamed to tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/Providers/LibComparatorSqlServer.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using BenchmarkDotNet.Attributes;
2-
using BenchmarkDotNet.Engines;
3-
41
using DotNet.Testcontainers.Containers;
52

63
using LinqToDB.EntityFrameworkCore;
@@ -11,11 +8,8 @@
118

129
using Testcontainers.MsSql;
1310

14-
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
11+
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark.Providers;
1512

16-
[MinColumn, MaxColumn, BaselineColumn]
17-
[MemoryDiagnoser]
18-
[SimpleJob(RunStrategy.Throughput, launchCount: 1, warmupCount: 0, iterationCount: 5)]
1913
public class LibComparatorSqlServer : LibComparator
2014
{
2115
protected override void ConfigureDbContext()

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/LibComparatorSqlite.cs renamed to tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/Providers/LibComparatorSqlite.cs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,3 @@
1-
using BenchmarkDotNet.Attributes;
2-
using BenchmarkDotNet.Engines;
3-
41
using DotNet.Testcontainers.Containers;
52

63
using LinqToDB.EntityFrameworkCore;
@@ -9,11 +6,8 @@
96

107
using PhenX.EntityFrameworkCore.BulkInsert.Sqlite;
118

12-
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
9+
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark.Providers;
1310

14-
[MinColumn, MaxColumn, BaselineColumn]
15-
[MemoryDiagnoser]
16-
[SimpleJob(RunStrategy.Throughput, launchCount: 1, warmupCount: 0, iterationCount: 5)]
1711
public class LibComparatorSqlite : LibComparator
1812
{
1913
protected override void ConfigureDbContext()

tests/PhenX.EntityFrameworkCore.BulkInsert.Benchmark/TestEntity.cs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,6 @@ public class TestEntity
1616
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
1717
public DateTimeOffset UpdatedAt { get; set; } = DateTimeOffset.UtcNow;
1818

19-
[Column(nameof(StringEnumValue), TypeName = "text")]
20-
public StringEnum StringEnumValue { get; set; }
21-
2219
public NumericEnum NumericEnumValue { get; set; }
2320
}
2421

@@ -27,9 +24,3 @@ public enum NumericEnum
2724
First = 1,
2825
Second = 2,
2926
}
30-
31-
public enum StringEnum
32-
{
33-
First,
34-
Second,
35-
}

0 commit comments

Comments
 (0)