sql.liter8.sh
Read the plan, not the query.
A real relational engine in your browser — parser, cost-based planner, statistics, volcano executor, MVCC. Write a query, see the rows it returned and the pages it cost. Free, local-first, no account required.
Every model writes SQL, all day, and writes it badly in a specific and predictable way: correct on a hundred rows, catastrophic on ten million. Grading here is not did you get the right rows. It is did you get the right rows without a four-million-row sequential scan.
Seven tracks
Foundations
SELECT, joins, three-valued logic, grouping, and the order clauses are evaluated in — which is not the order they are written.
Modelling
Keys and constraints as correctness rather than decoration. What a foreign key costs on write. Time zones stored wrong.
Indexes
B-tree anatomy, drawn. Composite column order. Why lower(email) cannot use an index on email, and why every index makes writes slower.
The planner
Reading EXPLAIN. Estimated versus actual, and what a 400x miss means. Stale statistics. When the planner is right and the query is wrong.
Transactions
Four anomalies, each reproduced live in two sessions. Deadlock as a wait-for graph. The bloat a long transaction leaves behind.
Production
The N+1 from the database side. Keyset versus offset pagination at page 20,000. Migrations that lock, and the patterns that do not.
Generated SQL
A query an agent wrote against a schema you know. What will it do at production scale — before you run it?
What is actually running
A relational engine in plain TypeScript: a lexer and recursive-descent parser, heap tables in real 8KB pages, B-tree indexes with a genuine node fanout, per-column statistics with an equi-depth histogram, a cost-based planner modelled on PostgreSQL, a volcano executor that counts every row and page it touches, and an MVCC transaction manager with deadlock detection. No server runs any of it. It runs in this tab.
The cost constants are a model, not a prediction. Rows, pages and loops are real counts the executor took; nothing here is printed in milliseconds, because that would imply it forecasts your production database.