Skip to content

Commit c4426b8

Browse files
author
MPCoreDeveloper
committed
IMPROVED: Phase 2A Benchmarks - Better cache metrics with multiple WHERE strategies
1 parent 8750640 commit c4426b8

File tree

1 file changed

+46
-33
lines changed

1 file changed

+46
-33
lines changed

tests/SharpCoreDB.Benchmarks/Phase2A_OptimizationBenchmark.cs

Lines changed: 46 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,10 @@ namespace SharpCoreDB.Benchmarks;
1010

1111
/// <summary>
1212
/// Phase 2A Optimization Benchmarks
13-
/// Measures actual performance improvements from:
14-
/// - Monday-Tuesday: WHERE Clause Caching (50-100x for repeated)
15-
/// - Wednesday: SELECT* StructRow Path (2-3x + 25x memory)
16-
/// - Thursday: Type Conversion Caching (5-10x)
17-
/// - Friday: Batch PK Validation (1.1-1.3x)
1813
///
19-
/// CRITICAL: Data is populated ONCE in GlobalSetup, not per-iteration!
20-
/// This measures QUERY performance, not insert performance.
14+
/// IMPORTANT: These benchmarks measure specific optimizations:
15+
/// - WHERE caching: Compilation is cached, but results still materialized
16+
/// - SELECT* path: Zero-copy StructRow vs Dictionary materialization
2117
/// </summary>
2218
[MemoryDiagnoser]
2319
[SimpleJob(warmupCount: 3, iterationCount: 5)]
@@ -38,8 +34,7 @@ public void Setup()
3834
// Create test table
3935
db.CreateUsersTable();
4036

41-
// CRITICAL: Populate data ONCE in GlobalSetup, not per-iteration
42-
// This ensures we measure QUERY performance, not insert performance
37+
// Populate data ONCE in GlobalSetup
4338
PopulateTestDataOnce();
4439
}
4540

@@ -52,25 +47,52 @@ public void Cleanup()
5247
#region Monday-Tuesday: WHERE Clause Caching Benchmarks
5348

5449
/// <summary>
55-
/// Repeated WHERE clause query - demonstrates cache benefits.
56-
/// First execution compiles and caches the predicate.
57-
/// Subsequent executions reuse cached predicate (99%+ hit rate).
58-
///
59-
/// Expected improvement: 50-100x for repeated queries
50+
/// Baseline: Single WHERE query (no cache benefit yet).
51+
/// This is the first execution where compilation happens.
6052
/// </summary>
61-
[Benchmark(Description = "WHERE caching: Execute same WHERE 100x (cache benefits)")]
62-
public int WhereClauseCaching_RepeatedQuery()
53+
[Benchmark(Description = "WHERE single query (baseline, no cache)")]
54+
public int WhereCaching_SingleQuery()
55+
{
56+
// Execute WHERE once - this compiles and caches the predicate
57+
var result = db.Database.ExecuteQuery("SELECT * FROM users WHERE age > 25");
58+
return result.Count;
59+
}
60+
61+
/// <summary>
62+
/// WHERE repeated 10x - tests cache effectiveness.
63+
/// After first execution, predicate should be cached.
64+
/// Expected: Similar performance to first query (filtering still needed).
65+
/// Cache benefit: Reduced compilation overhead.
66+
/// </summary>
67+
[Benchmark(Description = "WHERE repeated 10x (cache benefits)")]
68+
public int WhereCaching_Repeated10()
6369
{
64-
// Execute same WHERE query 100 times
65-
// First run: compiles and caches predicate
66-
// Runs 2-100: reuse cached predicate (99%+ cache hit rate)
6770
int totalCount = 0;
68-
69-
for (int i = 0; i < 100; i++)
71+
for (int i = 0; i < 10; i++)
7072
{
7173
var result = db.Database.ExecuteQuery("SELECT * FROM users WHERE age > 25");
7274
totalCount += result.Count;
7375
}
76+
return totalCount;
77+
}
78+
79+
/// <summary>
80+
/// Different WHERE clause - tests cache separation.
81+
/// Different predicate = new cache entry.
82+
/// Verifies cache works correctly for different queries.
83+
/// </summary>
84+
[Benchmark(Description = "WHERE different clause (tests cache isolation)")]
85+
public int WhereCaching_DifferentClause()
86+
{
87+
int totalCount = 0;
88+
89+
// Query 1: age > 25 (may use cached predicate)
90+
var result1 = db.Database.ExecuteQuery("SELECT * FROM users WHERE age > 25");
91+
totalCount += result1.Count;
92+
93+
// Query 2: age < 40 (different predicate = new cache entry)
94+
var result2 = db.Database.ExecuteQuery("SELECT * FROM users WHERE age < 40");
95+
totalCount += result2.Count;
7496

7597
return totalCount;
7698
}
@@ -82,8 +104,7 @@ public int WhereClauseCaching_RepeatedQuery()
82104
/// <summary>
83105
/// SELECT * using traditional Dictionary path (baseline).
84106
/// Each row materializes to Dictionary<string, object>.
85-
///
86-
/// Expected memory: ~200 bytes per row = 2MB for 10k rows
107+
/// Expected: ~200 bytes per row overhead
87108
/// </summary>
88109
[Benchmark(Description = "SELECT * Dictionary path (baseline)")]
89110
public int SelectDictionary_Path()
@@ -94,10 +115,8 @@ public int SelectDictionary_Path()
94115

95116
/// <summary>
96117
/// SELECT * using fast path with StructRow (optimized).
97-
/// Uses zero-copy StructRow instead of Dictionary.
98-
///
99-
/// Expected improvement: 2-3x faster, 25x less memory
100-
/// Expected memory: ~20 bytes per row = 200KB for 10k rows
118+
/// Uses zero-copy StructRow instead of Dictionary materialization.
119+
/// Expected: 2-3x faster, 25x less memory
101120
/// </summary>
102121
[Benchmark(Description = "SELECT * StructRow fast path (optimized)")]
103122
public int SelectStructRow_FastPath()
@@ -110,15 +129,10 @@ public int SelectStructRow_FastPath()
110129

111130
#region Helper Methods
112131

113-
/// <summary>
114-
/// Populate test data ONCE in GlobalSetup.
115-
/// This ensures benchmarks measure QUERY performance, not insert performance.
116-
/// </summary>
117132
private void PopulateTestDataOnce()
118133
{
119134
var random = new Random(42);
120135

121-
// Bulk insert to minimize insertion overhead
122136
for (int i = 0; i < DATASET_SIZE; i++)
123137
{
124138
var id = i;
@@ -137,7 +151,6 @@ INSERT INTO users (id, name, email, age, created_at, is_active)
137151
}
138152
catch (InvalidOperationException ex) when (ex.Message.Contains("Primary key"))
139153
{
140-
// Skip if row already exists
141154
continue;
142155
}
143156
}

0 commit comments

Comments
 (0)