Skip to content

Commit 69d9874

Browse files
author
MPCoreDeveloper
committed
benchmarks updated with reproducable facts
1 parent 8c8b8c3 commit 69d9874

35 files changed

+2769
-2908
lines changed

README.md

Lines changed: 199 additions & 281 deletions
Large diffs are not rendered by default.

SharpCoreDB.Benchmarks/Comparative/ComparativeInsertBenchmarks.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class ComparativeInsertBenchmarks : IDisposable
4343
// Track base ID per iteration to avoid conflicts
4444
private int currentBaseId = 0;
4545

46-
[Params(1, 10, 100, 1000)]
46+
[Params(1, 10, 100, 1000, 10000)]
4747
public int RecordCount { get; set; }
4848

4949
[GlobalSetup]
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
// Quick 10k benchmark test
2+
using SharpCoreDB.Benchmarks.Infrastructure;
3+
using Microsoft.Data.Sqlite;
4+
using LiteDB;
5+
using System.Diagnostics;
6+
7+
Console.WriteLine("???????????????????????????????????????????????????????");
8+
Console.WriteLine(" SharpCoreDB vs SQLite vs LiteDB - 10K Records Test");
9+
Console.WriteLine("???????????????????????????????????????????????????????\n");
10+
11+
var tempDir = Path.Combine(Path.GetTempPath(), $"dbBenchmark_{Guid.NewGuid()}");
12+
Directory.CreateDirectory(tempDir);
13+
14+
var dataGenerator = new TestDataGenerator();
15+
const int RecordCount = 10000;
16+
17+
try
18+
{
19+
// ??? SharpCoreDB (No Encryption) ???
20+
Console.WriteLine("? Testing SharpCoreDB (No Encryption)...");
21+
var dbPath = Path.Combine(tempDir, "sharpcore_noencrypt");
22+
using (var sharpDb = new BenchmarkDatabaseHelper(dbPath, enableEncryption: false))
23+
{
24+
sharpDb.CreateUsersTable();
25+
26+
var users = dataGenerator.GenerateUsers(RecordCount);
27+
var userList = users.Select(u => (u.Id, u.Name, u.Email, u.Age, u.CreatedAt, u.IsActive)).ToList();
28+
29+
var sw = Stopwatch.StartNew();
30+
sharpDb.InsertUsersTrueBatch(userList);
31+
sw.Stop();
32+
33+
Console.WriteLine($" Time: {sw.ElapsedMilliseconds}ms ({sw.ElapsedMilliseconds / (double)RecordCount:F3}ms per record)");
34+
Console.WriteLine($" Throughput: {RecordCount / sw.Elapsed.TotalSeconds:N0} records/sec\n");
35+
}
36+
37+
// ??? SharpCoreDB (Encrypted) ???
38+
Console.WriteLine("? Testing SharpCoreDB (Encrypted)...");
39+
var dbPathEnc = Path.Combine(tempDir, "sharpcore_encrypted");
40+
using (var sharpDbEnc = new BenchmarkDatabaseHelper(dbPathEnc, enableEncryption: true))
41+
{
42+
sharpDbEnc.CreateUsersTable();
43+
44+
var users = dataGenerator.GenerateUsers(RecordCount);
45+
var userList = users.Select(u => (u.Id, u.Name, u.Email, u.Age, u.CreatedAt, u.IsActive)).ToList();
46+
47+
var sw = Stopwatch.StartNew();
48+
sharpDbEnc.InsertUsersTrueBatch(userList);
49+
sw.Stop();
50+
51+
Console.WriteLine($" Time: {sw.ElapsedMilliseconds}ms ({sw.ElapsedMilliseconds / (double)RecordCount:F3}ms per record)");
52+
Console.WriteLine($" Throughput: {RecordCount / sw.Elapsed.TotalSeconds:N0} records/sec\n");
53+
}
54+
55+
// ??? SQLite Memory ???
56+
Console.WriteLine("? Testing SQLite (Memory)...");
57+
using (var sqliteConn = new SqliteConnection("Data Source=:memory:"))
58+
{
59+
sqliteConn.Open();
60+
61+
using (var cmd = sqliteConn.CreateCommand())
62+
{
63+
cmd.CommandText = @"
64+
CREATE TABLE users (
65+
id INTEGER PRIMARY KEY,
66+
name TEXT NOT NULL,
67+
email TEXT NOT NULL,
68+
age INTEGER NOT NULL,
69+
created_at TEXT NOT NULL,
70+
is_active INTEGER NOT NULL
71+
)";
72+
cmd.ExecuteNonQuery();
73+
}
74+
75+
var users = dataGenerator.GenerateUsers(RecordCount);
76+
var sw = Stopwatch.StartNew();
77+
78+
using (var transaction = sqliteConn.BeginTransaction())
79+
{
80+
using var cmd = sqliteConn.CreateCommand();
81+
cmd.CommandText = @"
82+
INSERT INTO users (id, name, email, age, created_at, is_active)
83+
VALUES (@id, @name, @email, @age, @created_at, @is_active)";
84+
85+
cmd.Parameters.Add("@id", SqliteType.Integer);
86+
cmd.Parameters.Add("@name", SqliteType.Text);
87+
cmd.Parameters.Add("@email", SqliteType.Text);
88+
cmd.Parameters.Add("@age", SqliteType.Integer);
89+
cmd.Parameters.Add("@created_at", SqliteType.Text);
90+
cmd.Parameters.Add("@is_active", SqliteType.Integer);
91+
92+
foreach (var user in users)
93+
{
94+
cmd.Parameters["@id"].Value = user.Id;
95+
cmd.Parameters["@name"].Value = user.Name;
96+
cmd.Parameters["@email"].Value = user.Email;
97+
cmd.Parameters["@age"].Value = user.Age;
98+
cmd.Parameters["@created_at"].Value = user.CreatedAt.ToString("o");
99+
cmd.Parameters["@is_active"].Value = user.IsActive ? 1 : 0;
100+
cmd.ExecuteNonQuery();
101+
}
102+
103+
transaction.Commit();
104+
}
105+
106+
sw.Stop();
107+
Console.WriteLine($" Time: {sw.ElapsedMilliseconds}ms ({sw.ElapsedMilliseconds / (double)RecordCount:F3}ms per record)");
108+
Console.WriteLine($" Throughput: {RecordCount / sw.Elapsed.TotalSeconds:N0} records/sec\n");
109+
}
110+
111+
// ??? SQLite File + WAL + FullSync ???
112+
Console.WriteLine("? Testing SQLite (File + WAL + FullSync)...");
113+
var sqliteFilePath = Path.Combine(tempDir, "sqlite_wal.db");
114+
using (var sqliteFile = new SqliteConnection($"Data Source={sqliteFilePath}"))
115+
{
116+
sqliteFile.Open();
117+
118+
using (var cmd = sqliteFile.CreateCommand())
119+
{
120+
cmd.CommandText = "PRAGMA journal_mode = WAL";
121+
cmd.ExecuteNonQuery();
122+
cmd.CommandText = "PRAGMA synchronous = FULL";
123+
cmd.ExecuteNonQuery();
124+
125+
cmd.CommandText = @"
126+
CREATE TABLE users (
127+
id INTEGER PRIMARY KEY,
128+
name TEXT NOT NULL,
129+
email TEXT NOT NULL,
130+
age INTEGER NOT NULL,
131+
created_at TEXT NOT NULL,
132+
is_active INTEGER NOT NULL
133+
)";
134+
cmd.ExecuteNonQuery();
135+
}
136+
137+
var users = dataGenerator.GenerateUsers(RecordCount);
138+
var sw = Stopwatch.StartNew();
139+
140+
using (var transaction = sqliteFile.BeginTransaction())
141+
{
142+
using var cmd = sqliteFile.CreateCommand();
143+
cmd.Transaction = transaction;
144+
cmd.CommandText = @"
145+
INSERT INTO users (id, name, email, age, created_at, is_active)
146+
VALUES (@id, @name, @email, @age, @created_at, @is_active)";
147+
148+
cmd.Parameters.Add("@id", SqliteType.Integer);
149+
cmd.Parameters.Add("@name", SqliteType.Text);
150+
cmd.Parameters.Add("@email", SqliteType.Text);
151+
cmd.Parameters.Add("@age", SqliteType.Integer);
152+
cmd.Parameters.Add("@created_at", SqliteType.Text);
153+
cmd.Parameters.Add("@is_active", SqliteType.Integer);
154+
155+
foreach (var user in users)
156+
{
157+
cmd.Parameters["@id"].Value = user.Id;
158+
cmd.Parameters["@name"].Value = user.Name;
159+
cmd.Parameters["@email"].Value = user.Email;
160+
cmd.Parameters["@age"].Value = user.Age;
161+
cmd.Parameters["@created_at"].Value = user.CreatedAt.ToString("o");
162+
cmd.Parameters["@is_active"].Value = user.IsActive ? 1 : 0;
163+
cmd.ExecuteNonQuery();
164+
}
165+
166+
transaction.Commit();
167+
}
168+
169+
sw.Stop();
170+
Console.WriteLine($" Time: {sw.ElapsedMilliseconds}ms ({sw.ElapsedMilliseconds / (double)RecordCount:F3}ms per record)");
171+
Console.WriteLine($" Throughput: {RecordCount / sw.Elapsed.TotalSeconds:N0} records/sec\n");
172+
}
173+
174+
// ??? LiteDB ???
175+
Console.WriteLine("? Testing LiteDB...");
176+
var liteDbPath = Path.Combine(tempDir, "litedb.db");
177+
using (var liteDb = new LiteDatabase(liteDbPath))
178+
{
179+
var collection = liteDb.GetCollection<TestDataGenerator.UserRecord>("users");
180+
181+
var users = dataGenerator.GenerateUsers(RecordCount);
182+
var sw = Stopwatch.StartNew();
183+
184+
collection.InsertBulk(users);
185+
186+
sw.Stop();
187+
Console.WriteLine($" Time: {sw.ElapsedMilliseconds}ms ({sw.ElapsedMilliseconds / (double)RecordCount:F3}ms per record)");
188+
Console.WriteLine($" Throughput: {RecordCount / sw.Elapsed.TotalSeconds:N0} records/sec\n");
189+
}
190+
191+
Console.WriteLine("???????????????????????????????????????????????????????");
192+
Console.WriteLine(" Benchmark Complete!");
193+
Console.WriteLine("???????????????????????????????????????????????????????");
194+
}
195+
finally
196+
{
197+
try
198+
{
199+
if (Directory.Exists(tempDir))
200+
{
201+
Directory.Delete(tempDir, recursive: true);
202+
}
203+
}
204+
catch
205+
{
206+
// Ignore cleanup errors
207+
}
208+
}

0 commit comments

Comments
 (0)