diff --git a/tests/benchmarks/SharpCoreDB.Benchmarks.Comparative/Program.cs b/tests/benchmarks/SharpCoreDB.Benchmarks.Comparative/Program.cs
index 1a6ac5f4..c3614872 100644
--- a/tests/benchmarks/SharpCoreDB.Benchmarks.Comparative/Program.cs
+++ b/tests/benchmarks/SharpCoreDB.Benchmarks.Comparative/Program.cs
@@ -347,12 +347,17 @@ static void RunInsertMicroBenchmark()
Console.WriteLine($" SQL/Direct overhead: {(sqlMedian / directMedian):F2}x");
}
- static DatabaseConfig BuildConfig(SharpCoreDB.Interfaces.StorageEngineType engineType)
+ static DatabaseConfig BuildConfig(SharpCoreDB.Interfaces.StorageEngineType engineType, bool fixedWidth = false)
{
return new DatabaseConfig
{
NoEncryptMode = true,
StorageEngineType = engineType,
+ // The fair PK comparison intentionally isolates the record-layout variable: the legacy
+ // arm opts out of the AutoFixedWidthRecords default so it measures true variable-length
+ // records; the fixed-width arm forces FixedWidthRecordLayout.
+ AutoFixedWidthRecords = !fixedWidth,
+ FixedWidthRecordLayout = fixedWidth,
UseGroupCommitWal = false,
EnableAdaptiveWalBatching = false,
HighSpeedInsertMode = true,
@@ -840,7 +845,7 @@ data TEXT
/// ExecuteBatchSQL (single transaction). This exercises the PK B-tree fast paths and the
/// recommended usage; the no-PK harness scenario above under-measures the engine on DML.
///
- static BenchmarkResult RunSharpCoreDBPk(SharpCoreDB.Interfaces.StorageEngineType engineType)
+ static BenchmarkResult RunSharpCoreDBPk(SharpCoreDB.Interfaces.StorageEngineType engineType, bool fixedWidth = false)
{
var dbPath = Path.Combine(Path.GetTempPath(), $"bench-sharpcoredb-pk-{Guid.NewGuid()}");
var result = new BenchmarkResult();
@@ -852,7 +857,7 @@ static BenchmarkResult RunSharpCoreDBPk(SharpCoreDB.Interfaces.StorageEngineType
var sp = services.BuildServiceProvider();
var factory = sp.GetRequiredService();
- var config = BuildConfig(engineType);
+ var config = BuildConfig(engineType, fixedWidth);
using var db = (SharpCoreDB.Database)factory.Create(
dbPath: dbPath,
@@ -962,22 +967,29 @@ static void RunPkComparison(SharpCoreDB.Interfaces.StorageEngineType engineType)
Console.WriteLine();
Console.WriteLine($"Engine: {engineLabel}");
- Console.WriteLine("━━━ SharpCoreDB (SQL, PK) ━━━");
+ Console.WriteLine("━━━ SharpCoreDB (SQL, PK, legacy variable-length) ━━━");
var scdb = RunSharpCoreDBPk(engineType);
Console.WriteLine();
+ Console.WriteLine("━━━ SharpCoreDB (SQL, PK, fixed-width) ━━━");
+ var scdbFw = RunSharpCoreDBPk(engineType, fixedWidth: true);
+ Console.WriteLine();
+
Console.WriteLine("━━━ SQLite (reference) ━━━");
var sqlite = RunSQLite();
Console.WriteLine();
Console.WriteLine("║ Database │ INSERT │ READ │ UPDATE │ DELETE ║");
Console.WriteLine($"║ SharpCoreDB │ {scdb.InsertOpsPerSec,10:N0} │ {scdb.ReadOpsPerSec,8:N0} │ {scdb.UpdateOpsPerSec,8:N0} │ {scdb.DeleteOpsPerSec,8:N0} ║");
+ Console.WriteLine($"║ SharpCoreDB FW│ {scdbFw.InsertOpsPerSec,10:N0} │ {scdbFw.ReadOpsPerSec,8:N0} │ {scdbFw.UpdateOpsPerSec,8:N0} │ {scdbFw.DeleteOpsPerSec,8:N0} ║");
Console.WriteLine($"║ SQLite │ {sqlite.InsertOpsPerSec,10:N0} │ {sqlite.ReadOpsPerSec,8:N0} │ {sqlite.UpdateOpsPerSec,8:N0} │ {sqlite.DeleteOpsPerSec,8:N0} ║");
- Console.WriteLine($"\n UPDATE gap: {sqlite.UpdateOpsPerSec / (double)scdb.UpdateOpsPerSec:F1}x DELETE gap: {sqlite.DeleteOpsPerSec / (double)scdb.DeleteOpsPerSec:F1}x");
+ Console.WriteLine($"\n UPDATE gap: SQLite vs legacy {sqlite.UpdateOpsPerSec / (double)scdb.UpdateOpsPerSec:F1}x vs fixed-width {sqlite.UpdateOpsPerSec / (double)scdbFw.UpdateOpsPerSec:F1}x");
+ Console.WriteLine($" DELETE gap: SQLite vs legacy {sqlite.DeleteOpsPerSec / (double)scdb.DeleteOpsPerSec:F1}x vs fixed-width {sqlite.DeleteOpsPerSec / (double)scdbFw.DeleteOpsPerSec:F1}x");
var results = new Dictionary
{
- ["SharpCoreDB (SQL, PK)"] = scdb,
+ ["SharpCoreDB (SQL, PK, legacy)"] = scdb,
+ ["SharpCoreDB (SQL, PK, fixed-width)"] = scdbFw,
["SQLite"] = sqlite,
};