use std::time::Instant;
use spg_engine::Engine;
fn build_5_table_engine() -> Engine {
let mut eng = Engine::new();
for tbl in ["t1", "t2", "t3", "t4", "t5"] {
eng.execute(&format!("CREATE TABLE {tbl} (id INT, peer INT)"))
.expect("create");
for i in 0..50_i64 {
let peer = (i + 1) % 50;
eng.execute(&format!("INSERT INTO {tbl} VALUES ({i}, {peer})"))
.expect("insert");
}
}
eng.execute("ANALYZE").expect("analyze");
eng
}
const COLD_RUNS: u32 = 200;
const HIT_RUNS: u32 = 200;
#[test]
fn prepare_cached_hit_under_1_3_of_cold_path() {
let _lock = crate::perf_lock();
let mut eng = build_5_table_engine();
let sql = "SELECT t1.id FROM t1 \
JOIN t2 ON t1.peer = t2.id \
JOIN t3 ON t2.peer = t3.id \
JOIN t4 ON t3.peer = t4.id \
JOIN t5 ON t4.peer = t5.id \
WHERE t1.id = 1";
let _ = eng.prepare_cached(sql).expect("warm");
let t0 = Instant::now();
for _ in 0..HIT_RUNS {
let stmt = eng.prepare_cached(sql).expect("hit");
std::hint::black_box(stmt);
}
let hit_total = t0.elapsed();
let hit_per_call = hit_total / HIT_RUNS;
let t1 = Instant::now();
for _ in 0..COLD_RUNS {
let stmt = eng.prepare(sql).expect("cold");
std::hint::black_box(stmt);
}
let cold_total = t1.elapsed();
let cold_per_call = cold_total / COLD_RUNS;
let ratio = hit_per_call.as_nanos() as f64 / cold_per_call.as_nanos() as f64;
eprintln!(
"v6.3.0 plan cache gate: hit/call = {} ns, cold/call = {} ns, ratio = {:.3}",
hit_per_call.as_nanos(),
cold_per_call.as_nanos(),
ratio
);
assert!(
ratio <= 0.33,
"hit path must be ≤ 1/3 of cold path; measured ratio = {ratio:.3} \
(hit/call = {} ns, cold/call = {} ns)",
hit_per_call.as_nanos(),
cold_per_call.as_nanos()
);
}