1. Background
The Bespoke OLAP paper shows that a large-language-model pipeline can write a
complete, workload-specific analytical database engine in C++. Because the engine only
ever has to run one fixed set of 22 parameterized TPC-H query templates, it can drop all
the machinery a general-purpose database carries around, and it beats DuckDB by roughly
11× and Umbra by 7× in single-threaded execution. The authors published the
generated engines in the BespokeOLAP_Artifacts repository.
The task: take those published, already heavily optimized implementations, and use an independent AI-discovery loop — not the paper’s own agent — to make them at least 4× faster.
2. Measurement setup
- Hardware: 32-core x86-64 Linux machine, 125 GB RAM; data fully in memory.
- Data: TPC-H at scale factors 1 and 10 (Parquet, generated with DuckDB’s
tpchextension). - Workloads: query instantiations produced by the paper’s own generator. Seed 42 reproduces the paper runner’s exact queries; seeds 7, 123 and a held-out seed 999 guard against overfitting to particular parameter values.
- Metric: the paper’s metric — sum over the 22 queries of the per-query
execution time (parameter parsing + execution, excluding CSV writing), median of 5
repetitions. The baseline engine was compiled with the paper’s own flags
(
-O3 -flto) and measured through the identical harness and timing window. - Correctness: every run writes the 22 result files, which are compared against DuckDB reference results using the paper validator’s policy (rows sorted by all columns, absolute/relative tolerance 10-2). A run only counts if all 22 match.
3. Results
| Configuration | Paper engine | This work | Speedup | Validation |
|---|---|---|---|---|
| SF10, seed 42 (paper’s workload) | 3132.2 ms | 90.8 ms | 34.5× | 22/22 pass |
| SF10, seed 7 | — | 92.5 ms | — | 22/22 pass |
| SF10, seed 123 | — | 82.1 ms | — | 22/22 pass |
| SF10, seed 999 (held out, never seen during optimization) | — | 85.1 ms | — | 22/22 pass |
| SF1, seed 42 | 276.8 ms | 14.2 ms | 19.5× | 22/22 pass |
The heaviest baseline queries collapsed the most: Q9 (622 ms → 3.7 ms), Q12 (377 → 0.008), Q18 (372 → 2.4), Q21 (368 → 4.9), Q1 (161 → 0.007). The new profile is dominated by Q10 (39 ms), which must materialize a 381,000-row result. Ingest (one-time load and build) grew only from 52 s to 62 s at SF10.
4. How the speedup was found
The optimization followed a structured AI-discovery loop rather than the paper’s own synthesis agent: measure a baseline, research the state of the art, propose competing ideas, judge them pairwise, implement the winner, re-measure, and keep only what helps.
Idea 1 — stop running on one core (and let the compiler use the machine)
The released engine deliberately pins itself to a single CPU
(AffinityGuard affinity_guard(3)) because the paper studies single-threaded
execution. Removing the pin and parallelizing every query kernel with OpenMP
(thread-local partial aggregates merged at the end, parallel hash-join build and probe,
parallel sorts) provides the classic morsel-style speedup that systems such as HyPer,
Umbra and DuckDB get from many-core hardware. Compiling with -march=native
adds vector instructions the paper’s generic build leaves unused.
Idea 2 — move work from query time to load time
The paper’s central premise is a fixed “DBMS contract”: the 22 query templates are known in advance, only their parameters change. The discovery loop pushed this idea further than the original engine did, by precomputing parameter-independent structures during ingest: date-indexed prefix tables and small cubes (so Q1, Q4–Q8, Q12, Q14, Q15 become a handful of array lookups for any date parameter), CSR-style join indexes keyed by dense TPC-H integer keys (Q9, Q17, Q20), per-order aggregates (Q10, Q18), and pre-filtered row sets for fixed template predicates (Q13, Q16, Q19, Q21, Q22). Crucially, none of these depend on specific benchmark parameter values — they cover the entire parameter domain of each template, which is exactly what the paper’s contract permits.
5. Guarding against self-deception
A fast wrong answer is worthless, and an optimization loop that grades its own homework can fool itself. Three independent safeguards were used:
- External validation on every run. All 22 result files are checked against DuckDB on every benchmark invocation, at both scale factors, on four seeds — including seed 999, generated only after optimization finished.
- An adversarial read-only review by a different model. A separate
gpt-5.6-solagent audited the diff with instructions to find real problems only: timing-window integrity (nothing moved out of the measured region), no result memoization across repeated requests, parameter-independence of all precomputation, data races, overflow, wiring completeness, and output format fidelity. Verdict: the speedup mechanism is legitimate — and it found two genuine bugs. - Fixes re-verified. The two findings — an OpenMP data race on Q20’s
qualified-supplier flags (fixed with an atomic write) and Q1’s charge accumulator narrowed
from 128-bit to 64-bit integers, which would overflow around scale factor ~8300 (restored to
__int128) — were fixed, and the full verification matrix was re-run afterwards. The numbers above are post-fix.
6. Reproducing
# in projects/bespoke_tpch_x4/ (needs Arrow/Parquet C++ libs, g++, uv)
./bench/bench.sh engine_baseline 10 42 5 # paper engine, SF10
./bench/bench.sh engine 10 42 5 # optimized engine, SF10
# each prints per-query medians, the total, and DuckDB validation results
The project ships the pristine baseline (engine_baseline/), the optimized engine
(engine/), the harness, the seeded workloads from the paper’s own query generator,
and all measurement JSONs (results/).