Skip to content

Eight Kilobytes · The lab

Don’t take our word for it.

Every measurement in this book came from a real PostgreSQL 18 server running the book's sample data. The lab is that server, packaged: one compose file, the seed, and a script for each chapter in which every claim is a check that either holds or fails loudly. If a chapter says an index takes a query from reading the whole table to reading a couple dozen pages, its lab measures that on your machine and stops with NOT PROVED if it doesn't hold.

Run it

You need Docker, and bash: any terminal on Linux or macOS, or Git Bash or WSL on Windows. Download the lab and run a chapter:

curl -L https://www.flagon.io/books/eight-kilobytes/lab.tar.gz | tar xz
cd eight-kilobytes-lab
./lab 16-btree

That one command does everything: it starts the lab's server if it isn't running (the first start seeds 2 million events, about a minute), runs the chapter's checks in a fresh copy of the data, and exits non-zero if any claim fails. A chapter's number or name works too (./lab 16, ./lab btree); ./lab on its own lists every chapter, and ./lab all runs them in reading order and lists any that failed. Labs can build indexes, update every row, or drop tables without stepping on each other. When you're done, docker compose down -v throws the whole thing away.

A few chapters need more than one server (a primary and a replica, a sharded cluster, a MySQL to compare against). ./lab lists them with a +. Their labs are shell scripts that start their own containers from their own compose files and remove them when they finish, pass or fail; they take a few minutes and more memory. Set KEEP=1 (KEEP=1 ./lab 37) to leave those servers running so you can look around afterwards.

To explore by hand, make yourself a copy and connect:

docker compose exec postgres psql -c "create database scratch template book"
docker compose exec postgres psql -d scratch

The server also listens on 127.0.0.1:5418 (user and password postgres) if you'd rather use your own client.

What a claim looks like

select lab.prove(
  'with an index on (project_id, created_at), the dashboard reads under 50 pages',
  lab.buffers($$ select * from events where project_id = 4242
                 order by created_at desc limit 20 $$) < 50
);

lab.buffers runs the query under EXPLAIN (ANALYZE, BUFFERS) and counts the pages it touched. lab.prove prints PROVED or stops the script. The helpers are in helpers.sql, and they're short enough to read in a minute. We check pages, rows, and plan shapes rather than milliseconds: timings depend on your hardware, page counts don't.

Chapter by chapter

2306 claims across 39 chapters.

ChapterLabClaims
Know the nouns first01-basics.sql23
Where the time goes02-latency.sql16
Everything is a page03-storage.sql64
The buffer cache decides what stays04-buffers.sql56
Updates are inserts05-mvcc.sql50
Keep your updates HOT06-hot.sql86
Write it down first07-wal.sql36
ACID, honestly08-acid.sh, 08-acid.sql58
Vacuum is not optional09-vacuum.sql45
Postgres is not MySQL10-not-mysql.sh109
Types are a contract11-types.sql79
Pick your keys once12-keys.sql60
Constraints, chosen on purpose13-relationships.sql81
You don't need another database (yet)14-models.sql64
Extensions worth knowing15-extensions.sh59
The B-tree does the heavy lifting16-btree.sql74
Beyond the B-tree17-more-indexes.sql84
Read the plan, not the clock18-explain.sql64
The planner is guessing19-planner.sql53
The cheapest plan wins20-plans.sql59
Queries that age well21-queries.sql60
Search without a search engine22-search.sh77
Code in the database23-functions.sql52
Everyone waits in line24-concurrency.sql70
Change the schema, keep the site25-migrations.sql128
Load it fast26-loading.sh, 26-loading.sql73
Connections aren't free27-connections.sql29
Measure honestly28-benchmarking.sh41
The settings that matter29-configuration.sql70
Watch it run30-observability.sql59
An untested backup is a rumor31-backups.sh43
Trust no tenant32-security.sql57
Someone else runs the box33-managed.sql31
Fix the work, then the box35-playbook.sql23
Scale up before you scale out36-scale.sql45
Copies of the truth37-replication.sh78
Partition for the delete38-partitioning.sql55
Shard last39-sharding.sh65
Where Postgres loses40-limits.sh30

Found one that doesn't hold?

That's a bug in the book, and we want it. Open an issue with the lab's output and your platform, or send a fix: the lab lives next to the chapters in the repository.