Skip to content

Commit 1f21ee4

Browse files
authored
Merge pull request #20 from PhenX/feature/add-linq2db-benchmark
Add Linq2DB to benchmarks
2 parents 4a6e942 + e74fc5b commit 1f21ee4

14 files changed

Lines changed: 241 additions & 246 deletions

README.md

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,10 @@ and https://entityframework-extensions.net/bulk-extensions), using optimized con
127127

128128
Legend :
129129
* `PhenX_EntityFrameworkCore_BulkInsert`: this library
130-
* `RawInsert`: no library, using the native provider API (SqlBulkCopy for SQL Server, BeginBinaryImport for PostgreSQL, raw inserts for SQLite)
130+
* `RawInsert`: naive implementation without any library, using the native provider API (SqlBulkCopy for SQL Server, BeginBinaryImport for PostgreSQL, raw inserts for SQLite)
131131
* `Z_EntityFramework_Extensions_EFCore`: https://entityframework-extensions.net/bulk-extensions
132132
* `EFCore_BulkExtensions`: https://github.com/borisdj/EFCore.BulkExtensions
133-
* `EFCore_SaveChanges`: EF Core SaveChanges classic method
133+
* `Linq2Db`: https://github.com/linq2db/linq2db
134134

135135
SQL Server results with 500 000 rows :
136136

@@ -144,6 +144,10 @@ SQLite results with 500 000 rows :
144144

145145
![bench-sqlite.png](https://raw.githubusercontent.com/PhenX/PhenX.EntityFrameworkCore.BulkInsert/refs/heads/master/images/bench-sqlite.png)
146146

147+
MySQL results with 500 000 rows :
148+
149+
![bench-mysql.png](https://raw.githubusercontent.com/PhenX/PhenX.EntityFrameworkCore.BulkInsert/refs/heads/master/images/bench-mysql.png)
150+
147151
## Contributing
148152

149153
Contributions are welcome! Please open issues or submit pull requests for bug fixes, features, or documentation improvements.

images/bench-mysql.png

26.9 KB
Loading

images/bench-postgresql.png

3.51 KB
Loading

images/bench-sqlite.png

4.27 KB
Loading

images/bench-sqlserver.png

3.7 KB
Loading
Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
using System.Data;
2+
3+
using Microsoft.Data.SqlClient;
4+
using Microsoft.Data.Sqlite;
5+
using Microsoft.EntityFrameworkCore;
6+
7+
using MySqlConnector;
8+
9+
using Npgsql;
10+
11+
namespace PhenX.EntityFrameworkCore.BulkInsert.Benchmark;
12+
13+
public abstract partial class LibComparator
14+
{
15+
private void RawInsertPostgreSql()
16+
{
17+
using var connection = (NpgsqlConnection)DbContext.Database.GetDbConnection();
18+
if (connection.State != ConnectionState.Open)
19+
{
20+
connection.Open();
21+
}
22+
23+
const string copyCommand = $"""
24+
COPY "{nameof(TestEntity)}" (
25+
"Name",
26+
"Price",
27+
"Identifier",
28+
"CreatedAt",
29+
"UpdatedAt",
30+
"NumericEnumValue"
31+
) FROM STDIN (FORMAT BINARY)
32+
""";
33+
34+
using var writer = connection.BeginBinaryImport(copyCommand);
35+
foreach (var entity in data)
36+
{
37+
writer.StartRow();
38+
writer.Write(entity.Name);
39+
writer.Write(entity.Price);
40+
writer.Write(entity.Identifier);
41+
writer.Write(entity.CreatedAt);
42+
writer.Write(entity.UpdatedAt);
43+
writer.Write((int)entity.NumericEnumValue);
44+
}
45+
46+
writer.Complete();
47+
}
48+
49+
private void RawInsertSqlite()
50+
{
51+
var connection = (SqliteConnection)DbContext.Database.GetDbConnection();
52+
if (connection.State != ConnectionState.Open)
53+
{
54+
connection.Open();
55+
}
56+
57+
using var transaction = connection.BeginTransaction();
58+
using var command = connection.CreateCommand();
59+
command.CommandText = $"""
60+
INSERT INTO "{nameof(TestEntity)}" (
61+
"Name",
62+
"Price",
63+
"Identifier",
64+
"CreatedAt",
65+
"UpdatedAt",
66+
"NumericEnumValue"
67+
) VALUES (@Name, @Price, @Identifier, @CreatedAt, @UpdatedAt, @NumericEnumValue)
68+
""";
69+
70+
command.Parameters.Add(new SqliteParameter("@Name", DbType.String));
71+
command.Parameters.Add(new SqliteParameter("@Price", DbType.Decimal));
72+
command.Parameters.Add(new SqliteParameter("@Identifier", DbType.Guid));
73+
command.Parameters.Add(new SqliteParameter("@CreatedAt", DbType.DateTime));
74+
command.Parameters.Add(new SqliteParameter("@UpdatedAt", DbType.DateTime2));
75+
command.Parameters.Add(new SqliteParameter("@NumericEnumValue", DbType.Int32));
76+
77+
foreach (var entity in data)
78+
{
79+
command.Parameters["@Name"].Value = entity.Name;
80+
command.Parameters["@Price"].Value = entity.Price;
81+
command.Parameters["@Identifier"].Value = entity.Identifier;
82+
command.Parameters["@CreatedAt"].Value = entity.CreatedAt;
83+
command.Parameters["@UpdatedAt"].Value = entity.UpdatedAt;
84+
command.Parameters["@NumericEnumValue"].Value = (int)entity.NumericEnumValue;
85+
86+
command.ExecuteNonQuery();
87+
}
88+
89+
transaction.Commit();
90+
}
91+
92+
private void RawInsertSqlServer()
93+
{
94+
var connection = (SqlConnection)DbContext.Database.GetDbConnection();
95+
if (connection.State != ConnectionState.Open)
96+
{
97+
connection.Open();
98+
}
99+
100+
using var bulkCopy = new SqlBulkCopy(connection);
101+
102+
bulkCopy.DestinationTableName = nameof(TestEntity);
103+
bulkCopy.BatchSize = 50_000;
104+
bulkCopy.BulkCopyTimeout = 60;
105+
106+
bulkCopy.ColumnMappings.Add("Name", "Name");
107+
bulkCopy.ColumnMappings.Add("Price", "Price");
108+
bulkCopy.ColumnMappings.Add("Identifier", "Identifier");
109+
bulkCopy.ColumnMappings.Add("CreatedAt", "CreatedAt");
110+
bulkCopy.ColumnMappings.Add("UpdatedAt", "UpdatedAt");
111+
bulkCopy.ColumnMappings.Add("NumericEnumValue", "NumericEnumValue");
112+
113+
var dataTable = new DataTable();
114+
dataTable.Columns.Add("Name", typeof(string));
115+
dataTable.Columns.Add("Price", typeof(decimal));
116+
dataTable.Columns.Add("Identifier", typeof(Guid));
117+
dataTable.Columns.Add("CreatedAt", typeof(DateTime));
118+
dataTable.Columns.Add("UpdatedAt", typeof(DateTimeOffset));
119+
dataTable.Columns.Add("NumericEnumValue", typeof(int));
120+
121+
foreach (var entity in data)
122+
{
123+
var row = dataTable.NewRow();
124+
row["Name"] = entity.Name;
125+
row["Price"] = entity.Price;
126+
row["Identifier"] = entity.Identifier;
127+
row["CreatedAt"] = entity.CreatedAt;
128+
row["UpdatedAt"] = entity.UpdatedAt;
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;
182+
row["NumericEnumValue"] = (int)entity.NumericEnumValue;
183+
dataTable.Rows.Add(row);
184+
185+
if (dataTable.Rows.Count >= 50_000)
186+
{
187+
bulkCopy.WriteToServer(dataTable);
188+
dataTable.Clear();
189+
}
190+
}
191+
192+
if (dataTable.Rows.Count > 0)
193+
{
194+
bulkCopy.WriteToServer(dataTable);
195+
}
196+
}
197+
}

0 commit comments

Comments
 (0)