Skip to content
Self-Driving DB LabCOMP90050 · G40

Methods

How the lab was built and checked

Where every number on this site comes from, how it was measured, what it assumes and where it is weak. The optional AI feature is documented here too: what it does, what it never does, and how its advice is measured.

Database journey

One Louvre database, from design to self-tuning

In 2020 Sunchuangyu (Rin) Huang designed this database for an individual INFO20003 assignment. In 2023, COMP90050 taught what a database does with a design once it runs. The arena now loads the INFO20003 file byte for byte and lets the survey's index advisors, and your own LLM if you bring a key, tune it.

  1. 2020Semester 1

    INFO20003 Database Systems

    Design the database

    A ticketing and visitor database for the Louvre, designed from a written brief: who buys what, which entrance and wing a ticket passes, audio guides, timed exhibition slots.

    • Conceptual ER model (Chen)
    • Crow's foot physical model
    • Relational schema
    • SQL
  2. 2023Winter term

    COMP90050 Advanced Database Systems

    Make it run well, on its own

    What happens after design: how rows are stored, how indexes and the optimiser decide a query's cost, and how a self-driving database chooses its own indexes.

    • Storage
    • Indexing
    • Query optimisation
    • Self-driving index selection

Shared file: louvre.db · 19 tables · about 66,000 synthetic rows · SHA-256 b762146e2601… · why the arena drops its indexes (DR-004)

Where the data comes from

Data provenance

The 2023 coursework. The survey's claims, its Table 2 (Perera et al.'s comparison of a bandit with a commercial tool) and its corrected citations are quoted from Group 40's report as written. A parity test pins every number the site repeats. The lab adds analysis around those results and does not change them.

The TPC-H-like database is generated in the browser from a seed, following the TPC-H specification's value domains, date rules and table ratios at 3,000 to 15,000 orders. No code or data from TPC's dbgen is used.

The Louvre database is the file from Rin's 2020 INFO20003 assignment, as rebuilt by its 2026 revival with five years of synthetic museum activity (seed 20200403). The lab ships it gzip-compressed and a unit test checks the uncompressed file's SHA-256 (b762146e2601e0c3…), which matches the public download on the INFO20003 site. See the data card and DR-004.

Workloads and the forecasting trace are generated from seeds, so every run on the site can be reproduced from the seed it shows. Nothing a visitor does is sent to a server, because there is none.

What runs

Methods

Every experiment runs in a Web Worker on SQLite 3.49 compiled to WebAssembly (sql.js). The arena replays the same rounds of queries once per advisor. Before each round an advisor may build or drop indexes, and total workload time is the sum of recommendation, index creation and query execution, the breakdown of the report's Table 2.

  • Offline advisors (DROP, AutoAdmin, DB2 Advisor, CoPhy) ask a what-if cost model about hypothetical indexes. Following Perera et al.'s protocol, they tune at the start of round 2 with round 1 as their workload and again whenever the template mix changes by more than half.
  • The C²UCB bandit learns only from runtimes it observes (DR-003).
  • The LLM advisor proposes a configuration once, from the schema, round 1 and SQLite's plans. The lab validates it, a person reviews it, and it is built at the start of round 2 (DR-005).
  • The hindsight reference builds, before round 1, the configuration CoPhy's branch and bound finds best under the what-if model for the whole workload. Its node budget is large enough to prove that optimal on every setting the benchmark offers at the default scale, and the benchmark says so whenever it does not. It exists to measure regret.
  • Engines. Measured SQLite times every build and query on the visitor's machine. The simulated engine charges plans with a second set of cost constants plus seeded noise (DR-002).
  • Workloads. Static, shifting, random and HTAP follow Perera et al. The drifting workload, new in 2026, puts a share of each round (the drift) on the current phase's group and spreads the rest over all twelve read templates. Drift 0 is the static mix and drift 1 the shifting mix.
  • Forecasting. QB5000's templatiser, clusterer, linear and kernel regression and HYBRID rule on a synthetic trace, feeding AutoAdmin window by window.

How results are compared

Evaluation design

A single arena run is one sample. The benchmark runs every advisor on R replicate workloads (10 by default), where replicate r uses workload seed s + r. Inside a replicate every advisor replays the same queries, in a seeded random order after one discarded warm-up replicate, so each replicate is a matched pair and comparisons are paired.

  • Means of cumulative workload time per advisor carry 95% percentile-bootstrap intervals (B = 2,000, resampling seed 90050).
  • Two kinds of interval. In the browser the intervals resample one session's replicates, so they describe workload-to-workload variation in that session only. Running the same seeds again in a fresh session moves measured times by more than that. The published numbers therefore come from 5 independent sessions (a fresh process each) over the same seeds, with a pigeonhole bootstrap that resamples sessions and workload seeds independently (Owen 2007), and each one comes with the range of single-session estimates.
  • Paired comparisons against the greedy what-if advisor (AutoAdmin) report the mean difference and the ratio of means, both with intervals from resampling whole pairs, Cohen's d_z, an exact two-sided sign test and the share of replicates won with a Wilson interval. The page shows effect sizes first because ten replicates cannot give a sign-test p below 0.002.
  • Two metrics. Total time includes recommendation. Build + run leaves it out, which matters for the LLM, whose response time is network and provider latency.
  • Regret is the bandit's cumulative time above the hindsight reference, round by round, with pointwise bootstrap bands, and a count of the replicates where the reference was proven optimal.
  • Drift sensitivity repeats everything at drift 0, 0.25, 0.5, 0.75 and 1.
  • The invalid-proposal rate of the LLM advisor is reported separately for each provider, model (the one that answered), prompt version and dataset, never pooled. The share of calls with an unusable reply or any rejection gets a Wilson interval, because calls are independent. The share of proposed indexes the validator rejects gets a bootstrap interval that resamples whole calls, because indexes from one reply share its mistakes. Provider, network and cancelled calls are left out.
  • Forecasting is summarised over ten seeded traces, with paired comparisons against linear regression and against reactive tuning.

The statistical helpers live in web/src/lib/stats/. Their unit tests compare them with numpy, scipy and statsmodels (scripts/verify_stats.py, run with uv) and with base R (scripts/verify_stats.R). Analytic quantities agree to about 1e-10. Bootstrap intervals agree with scipy's within Monte Carlo error.

What the benchmark found

Headline results

Measured SQLite, 5 sessions x 10 workload seeds, 25 rounds, 200% budget, means in milliseconds with 95% pigeonhole-bootstrap intervals. Negative change means the bandit was faster than greedy; under each change is the range of the 5 single-session estimates. These numbers come from pnpm bench:report (darwin arm64 (Apple M4), Node v26.11.0, 9 October 2026). A browser on another machine gives different absolute times.

Dataset · workloadNo index (ms)Greedy (ms)Bandit (ms)Bandit vs greedy, totalBandit vs greedy, build + run
TPC-H-like (S) · static534[530, 541]177[175, 179]137[134, 141]−23% [−24%, −21%]sessions −23% to −22%+12% [+10%, +14%]sessions +11% to +14%
TPC-H-like (S) · shifting616[603, 638]170[165, 180]217[211, 226]+27% [+22%, +32%]sessions +25% to +29%+32% [+26%, +37%]sessions +29% to +34%
TPC-H-like (S) · HTAP1093[1070, 1126]223[217, 237]193[187, 203]−14% [−18%, −9%]sessions −15% to −12%+18% [+10%, +25%]sessions +15% to +20%
Louvre · static211[204, 222]152[150, 155]81[75, 89]−47% [−50%, −42%]sessions −51% to −39%+49% [+45%, +54%]sessions +46% to +53%
Louvre · shifting223[214, 240]72[68, 81]90[84, 101]+25% [+12%, +38%]sessions +14% to +38%+49% [+30%, +64%]sessions +31% to +65%
Louvre · HTAP251[245, 264]177[173, 183]89[83, 104]−50% [−53%, −43%]sessions −52% to −42%+47% [+36%, +56%]sessions +41% to +51%

On static and HTAP workloads the bandit beat greedy on total time but lost on build + run time. Its advantage is that it never pays for a what-if search, which weighs a lot when the whole workload takes a few hundred milliseconds. On shifting workloads it lost on both. The decision records give the details.

What the numbers rely on

Assumptions

  • The what-if model assumes uniform, independent columns and fixed per-row costs fitted on one laptop.
  • Recommendation time is the advisors' own JavaScript run time plus 0.02 ms per what-if call, standing in for an optimiser call that would take milliseconds in a server DBMS.
  • Replicates differ only in query literals and noise. The data, schema and template mix stay fixed. The published intervals cover workload-to-workload and run-to-run variation on one machine, not machine-to-machine variation.
  • Every index is a plain B-tree in SQLite. There are no INCLUDE columns, partial indexes or materialised views.
  • The Louvre data is synthetic and small (about two visiting parties a day), and the museum workload's mix and parameters are my own choices.

Where it is weak

Limitations

  • Workloads take hundreds of milliseconds, so recommendation time weighs far more than in the papers the survey quoted. Rankings on total time can flip on build + run time.
  • In the browser, intervals come from one session's replicates and leave out run-to-run variation. Across 5 sessions on the author's machine, single-session estimates of the bandit's total-time change against greedy spread by up to 24 percentage points: +14% to +38% on Louvre shifting, against −23% to −22% on static TPC-H-like. More replicates narrow one session's intervals without capturing that, so re-run the benchmark before trusting a small difference. Percentile intervals from ten workloads are also somewhat too narrow.
  • The simulated engine's constants were fitted on TPC-H-like data and overestimate the Louvre's no-index time by about 21%.
  • The forecasting lab uses synthetic traces and no LSTM.
  • LLM results exist only in the browsers of visitors who bring a key. None are published here.
  • Measured times depend on the visitor's hardware, browser and other open tabs.

Next time

What I'd change

  • Run the benchmark at larger scale outside the browser, where execution dominates as it does in the papers.
  • Calibrate the cost constants per dataset and per machine in a short warm-up.
  • Re-consult the LLM after each workload shift and compare it with re-invoked offline tools.
  • Add Monte Carlo tree search, the report's other learned index tuner.
  • Offer the INFO20003 schema's own seven indexes as an as-designed configuration to compare with the advisors.

Transparency

AI use statement

The site has one optional AI feature, the LLM index advisor on the arena and benchmark pages. Everything else works without it.

What the AI does

  • Proposes up to 12 secondary indexes of 1 to 4 columns, with a one-sentence rationale each, in a fixed JSON structure.
  • Explains its overall strategy in a short note.

What it never does

  • Write or run SQL. The lab writes every CREATE INDEX itself.
  • Build anything a person has not accepted.
  • See your key or your audit log.
  • Get anything about you in its prompt (see below for what any web request reveals).
  • Data sent to the provider. The schema with row counts and distinct-value counts, round 1 of the workload (SQL with literals from the synthetic data, and each template's share of estimated cost), SQLite's query plans and the storage budget. The full message is kept in the audit log. The prompt contains nothing about you, but the call goes straight from your browser, so, as with any web request, the provider also sees your IP address and browser headers (such as the User-Agent and this site's Origin), under its own privacy terms.
  • Models. Anthropic by default (Claude Haiku 4.5 or Claude Sonnet 5.5), or any OpenAI model id (default gpt-5-mini). Prompt version ixadv-2026-10-09. With Claude Sonnet 5.5 the refusal fallback is on by default: a request Sonnet declines may be re-run on another Claude model, and the audit log records the model that answered. AI settings can turn it off.
  • Your key. Kept in sessionStorage, or in localStorage only if you tick “remember on this device”. It is sent only to the provider, directly from your browser, and “forget key” removes it. Calls are billed to your key.
  • Human in the loop. Every output is labelled AI-generated. The validator rejects anything outside the schema or the budget with a reason, and a person accepts, edits or rejects the rest before anything is built. An accepted configuration is measured only on the settings the model was shown: changing them discards it, and the drift sweep leaves it out.
  • Audit trail. Every call that leaves the browser (failed and cancelled ones included), every decision and every measurement is appended to an audit log in your browser (IndexedDB), viewable and exportable as JSON or CSV at /ai-log. The key is never written to it. If a record cannot be written, for example because the browser blocks site storage, the page says so and the proposal cannot be accepted.
  • Frameworks. The design is informed by the Australian Government's policy for the responsible use of AI in government, the EU AI Act's transparency principles and the NIST AI Risk Management Framework. It is not a claim of compliance with any of them.

Models

Model card: the models inside the Self-Driving DB Lab

The lab contains four models. Two make decisions (the C²UCB bandit and the optional LLM index advisor), one estimates costs for the offline advisors (the what-if cost model), and three small forecasters predict query arrivals (QB5000's linear regression, kernel regression and HYBRID rule). None of them is trained on personal data, and none of them is used outside this teaching and portfolio site.

Every interval below is a 95% interval. Proportions use Wilson intervals. Replicate r uses workload seed 2023 + r. Measured times come from docs/benchmark-numbers.json, which pnpm bench:report regenerates with the lab's own code (sql.js under Node 26 on an Apple M4 laptop, the same WebAssembly build a browser runs). It runs five independent sessions (a fresh process each) over the same 10 seeds, with the advisors in a seeded random order after a discarded warm-up replicate. Benchmark means and ratios use a pigeonhole percentile bootstrap over sessions and seeds (B = 2000, resampling seed 90050), which includes run-to-run variation, and the file gives the range of single-session estimates next to each. The forecasting intervals are percentile-bootstrap intervals over traces. A visitor's browser gives different absolute times, and its intervals describe one session only.

1. What-if cost model

What it is. A System R style cost model (web/src/lib/engine/cost-model.ts) that estimates a query's cost, its access path and an index's size and build time for any hypothetical configuration. AutoAdmin, DB2 Advisor, DROP and CoPhy ask it every what-if question, and the SQL console's what-if panel shows its estimates.

Intended use. Ranking candidate index configurations for the advisors in this lab. It is not a general SQLite cost model.

Provenance of its constants. Ten constants (per row scanned, per index entry, per rowid fetch, per B-tree level and so on) were fitted to warmed-up median timings of sql.js 1.14 (SQLite 3.49) under Node on an Apple-silicon laptop, on the TPC-H-like data. Selectivities come from distinct-value counts and value ranges computed from the loaded rows, assuming uniform and independent columns.

Evaluation.

  • Plan agreement with SQLite's planner: the unit tests check 10 hand-picked (template, index) cases on the TPC-H-like data and 13 on the Louvre data, and the model picks the same index as SQLite in all of them. The tests must pass for CI to be green and cover the templates I expected to agree, so they are a regression check, not an agreement rate. Templates Q6, Q7 and Q9 (TPC-H-like) and L9 (Louvre) are not covered. An agreement rate would need a random sample of (query, candidate index) pairs, with disagreements recorded rather than failing the build.
  • Index sizes: within 10% of SQLite's page counts on the tested TPC-H-like indexes and within 15% on the Louvre ones.
  • Timings: with no indexes, the simulated engine (built on this model) estimates 976 ms (939 to 1010) for 25 static TPC-H-like rounds where measured SQLite takes 534 ms (530 to 541), and 255 ms where SQLite takes 211 ms (204 to 222) on the Louvre data. It ranks configurations better than it predicts milliseconds.

Known failure modes. Correlated columns and skewed values break the uniform-independence assumption. SQLite's skip-scan plans are not modelled, so the arena switches skip-scan off by default (the advanced settings can turn it on to show the surprise). Constants fitted on one laptop and on TPC-H-like data drift on other machines and on text timestamps.

2. C²UCB bandit index tuner

What it is. The contextual combinatorial bandit of Perera et al. (IEEE TKDE 2023), ported in web/src/lib/advisors/mab/. It never asks the what-if model anything and learns only from execution times it observes. DR-003 records the formulation.

Intended use. Online index tuning in the arena and the benchmark, to compare a learned tuner with the heuristic and integer-programming advisors under one stopwatch.

Training data. None before a run. It starts every run empty and learns from that run's observed runtimes. Its hyperparameters (α = 1, λ = 0.5, α shrinking 5% per round) are the authors' published TPC-H settings, not tuned on this lab's data.

Evaluation (measured SQLite, five sessions of 10 replicates, 25 rounds, 200% budget, against AutoAdmin's greedy what-if search). "Single sessions" gives the lowest and highest single-session estimate of the change.

DatasetWorkloadBandit vs greedy, total timeSingle sessionsFinal regret vs hindsight reference
TPC-H-like (S)Static23% less (24% to 21% less)23% to 22% less56 ms (54 to 60), 70% of the reference's total
TPC-H-like (S)Shifting27% more (22% to 32% more)25% to 29% more134 ms (130 to 143), 163%
TPC-H-like (S)HTAP14% less (18% to 9% less)15% to 12% less88 ms (81 to 92), 83%
LouvreStatic47% less (50% to 42% less)51% to 39% less47 ms (40 to 55), 136%
LouvreShifting25% more (12% to 38% more)14% to 38% more57 ms (52 to 68), 173%
LouvreHTAP50% less (53% to 43% less)52% to 42% less50 ms (44 to 64), 127%

The hindsight reference was proven optimal in all 50 replicate runs of every row. On build + run time without recommendation, the bandit was slower than greedy on the same static runs (12% on TPC-H-like, 10% to 14%, and 49% on Louvre, 45% to 54%). Its total-time advantage comes from never running a what-if search, and DR-002 explains why that weighs so much on workloads this small.

Known failure modes. It relearns from scratch after a large workload shift, so it loses on shifting workloads. Tables under 1,000 rows are never indexed. At budgets of 100% or less its first choices can crowd out later ones.

3. QB5000 forecasters

What they are. Linear regression on the last 24 hours, Nadaraya-Watson kernel regression on the last 168 hours, and QB5000's HYBRID rule that switches to kernel regression when it predicts a spike (web/src/lib/forecast/). QB5000's LSTM is not implemented, and linear regression stands in for its LR plus LSTM ensemble.

Training data. Two weeks of a synthetic hourly trace of the arena's twelve TPC-H-like templates, with daily and weekly cycles, a nightly batch, a Monday spike and noise. Templates are clustered by their training history.

Evaluation (test week, log mean squared error averaged over clusters, 10 traces from seeds 2023 to 2032).

  • LR 0.343 (0.334 to 0.352), KR 0.635 (0.628 to 0.641), HYBRID 0.333 (0.323 to 0.343).
  • HYBRID against LR: 3% lower error, with an interval from 7% lower to 1% higher. Ten traces do not settle this comparison. KR was worse than LR on all 10 traces (85% higher error, 81% to 89%).
  • Forecast-driven index tuning cost 9% less than reactive tuning in estimated query and build cost (10% to 7% less, 10 of 10 traces), and an oracle that knows the next window cost 15% less.

Known failure modes. The trace is synthetic and regular, so these errors flatter all three models compared with real traces. The tuning-loop costs are what-if estimates, not measured runtimes.

4. LLM index advisor (bring your own key)

What it is. A third-party large language model chosen by the visitor (Claude Haiku 4.5 by default, Claude Sonnet 5.5, or an OpenAI model id), called from the visitor's browser with the visitor's own key. It proposes indexes in a fixed JSON structure. DR-005 records the design.

Intended use. An optional advisor whose proposals are validated, reviewed by a person and then measured against the lab's own advisors. It never acts on the database directly.

Training data. Not known to this project and not changed by it. The site does not train or fine-tune anything.

Evaluation. The benchmark measures any accepted proposal with the same seeded workloads and paired statistics as the other advisors, only on the settings the model was shown, and records the result in the browser's audit log. The invalid-proposal rate is reported separately for each provider, model (the one that answered), prompt version and dataset, never pooled. The share of calls with any rejected index or an unusable reply gets a Wilson interval, since calls are independent. The share of proposed indexes the validator rejected gets a percentile-bootstrap interval that resamples whole calls, since indexes from one reply share its mistakes. No results are published here because there is no budget for API calls.

Known failure modes. Columns that do not exist on the named table (likely on the Louvre schema, where names like ticket_id repeat across tables), indexes on a table's primary key, configurations over the storage budget, malformed or truncated replies, refusals and different answers to the same prompt. The validator catches the first four, the client reports the rest, and the audit log keeps the evidence.

Ethical considerations

  • All data the models see is synthetic: the TPC-H-like rows, the generated workloads and trace, and the Louvre database from INFO20003, whose names and card digits are invented (see the data card).
  • The LLM advisor sends the schema, its statistics, one round of SQL with literals from the synthetic data, and query plans to the visitor's chosen provider. The prompt contains nothing about the visitor. As with any direct web request, the provider sees the visitor's IP address and browser headers, under its own privacy terms.
  • With Claude Sonnet 5.5 the refusal fallback is on by default, so a request Sonnet declines may be re-run on another Claude model. The audit log records the model that answered, and the invalid-proposal rate scores it separately.
  • API keys stay in the visitor's browser and are never written to the audit log. Calls are billed to the visitor's key, and the site says so before the first call.
  • Every model output is labelled "AI-generated", and a person accepts, edits or rejects every proposal before anything is built. A proposal whose call could not be written to the audit log cannot be accepted. The approach is informed by the Australian Government's policy for the responsible use of AI in government, the EU AI Act's transparency principles and the NIST AI Risk Management Framework. It is not a claim of compliance with any of them.

Data

Data card: the datasets of the Self-Driving DB Lab

Every dataset in the lab is synthetic. No real customer, visitor, payment or query-log data was used at any stage.

TPC-H-like database

Provenance. Generated in the browser (and in the tests) by web/src/lib/db/generate.ts from a seed, following the TPC-H specification's value domains, date rules and cardinality ratios. No code or data from TPC's dbgen is used.

Contents. Seven tables (region, nation, supplier, customer, part, orders, lineitem) at three sizes: 3,000, 7,500 or 15,000 orders, with about four line items per order. Only primary keys are declared, so every secondary index is an advisor's choice.

Intended use. The arena, the benchmark, the SQL console and the forecasting lab.

Known limitations. Values are uniform unless a skew is set, so the cost model's uniformity assumption fits it better than it would fit real data. At browser scale a full scan takes milliseconds.

Louvre ticketing database (from INFO20003)

Provenance. The file web/public/data/louvre.db.gz is the INFO20003 revival's web/data/louvre.db (main branch, commit c0312f0, last changed in 6ec72a8), compressed with gzip. The uncompressed file is 3,436,544 bytes with SHA-256 b762146e2601e0c333991e203caed7ce65d76c0a9520fe1ba200f50a5331bece, which a unit test checks. It is byte-identical to the public download at info20003-louvre-ops-db.vercel.app/data/louvre.db. It was generated by a seeded simulation (seed 20200403) of five years of museum activity, 1 March 2015 to 29 February 2020. Only the 2020 brief's fixed facts are real: five entrances, three wings, 13 audio-guide languages, prices and the exhibition slot size.

Contents. About 66,000 rows in 19 tables: payments with masked card or cash details, orders and order lines, tickets, entrance and wing scans, audio-guide devices and hires, exhibitions, slots, bookings and Hall Napoléon admissions. Names are drawn from short invented lists and card numbers are stored as first and last four digits only.

How the lab uses it. Every table and row is loaded into the lab's own tables with only INTEGER PRIMARY KEYs (DR-004). A museum workload of twelve reads and one UPDATE draws its literals from the data's own statistics and from real column values (barcodes, payment methods, languages, exhibition dates).

Known limitations. About two visiting parties a day, far below the real museum's volume, so timings describe a small database. Every distribution (seasonality, transport mode, guide hire rates) is an assumption of the 2020 revival. Results describe the simulation, not the Louvre.

Workloads and the forecasting trace

Query instances are generated from templates and seeds (web/src/lib/workload/, web/src/lib/datasets/louvre/), so every arena run and benchmark replicate can be reproduced from its seed. The forecasting lab's three-week trace is generated from a seed by web/src/lib/forecast/trace.ts with daily and weekly cycles, a nightly batch, a Monday spike and noise. The traces QB5000 was evaluated on are not public, which is why it is synthetic.

What the site stores

Nothing on a server: the site is static. Each browser tab builds its own in-memory SQLite database and discards it when the tab closes. The only persistent records are the optional AI settings (in localStorage), the visitor's key if they choose to keep it, and the AI audit log (in IndexedDB), all in the visitor's own browser.

Ethical considerations

The datasets are synthetic by design, so they can be published, sent to an AI provider by a visitor who chooses to, and queried by anyone. They must not be presented as real attendance, revenue or business data.

Why it is built this way

Decision records