study
study
Books you read, turned into labs you run. Each exercise makes you predict a specific behavior, run the real thing, and check your prediction against a real transcript — the gap is where the mental model gets built.
Designing Data-Intensive Applications
Kleppmann & Riccomini, 2nd ed. (2025).
-
Ch. 2 — Tail-Latency Amplification
— a backend call slow just 1% of the time, fanned out to 100 parallel calls, makes 63% of end-user requests slow. Predict "still ~99% fast"; measure ~37%.
-
Ch. 2 — The Mean Hides the Tail
— for right-skewed latency, 69% of requests are faster than "average," yet p99 is 6× the mean. The average overstates the typical request and understates the tail at once.
-
Ch. 2 — Averaging Percentiles Is a Lie
— average ten servers' p99s and you land 21% below the true pooled p99. Predict "close enough"; measure the gap.
-
Ch. 3 — ADD COLUMN Is Instant, Until It Isn't
— adding a
NOT NULL column with a default to a 10M-row Postgres table takes 0.8 ms, not the full rewrite everyone predicts — but a volatile default rewrites it in ~8 s.
-
Ch. 3 — Reachability Needs Recursion
— "is Boise in North America?" A two-level join silently answers no (it's 4 hops deep);
WITH RECURSIVE gets it right at any depth. A fixed join count can't express transitive reachability.
-
Ch. 4 — The Column Store Reads Only What It Needs
— a 2-column query over a 30-column table makes a row store read 100% of the data and a column store 0.6% — 165× less — from layout alone.
-
Ch. 4 — Sorting Rows Changes How Big They Are
— a column store is 5.5× smaller than the row store; reordering the same rows shrinks it another 1.4×, one column collapsing 30×. Sort order is a compression lever.
-
Ch. 4 — Ten Bits per Key Buys a 1% Miss Rate
— a Bloom filter needs ~10 bits (not bytes) per key for a 0.8% false-positive rate, matching the formula — and its size is independent of key length.
-
Ch. 4 — The Same Rows Cost 4× More in Random Order
— load 10M rows into a B-tree in random key order and it's 4× slower with a 31% bigger index (69% vs 90% leaf fill). Why LSM writes sequentially.
-
Ch. 4 — The Covering Index That Still Reads the Heap
— a covering index keeps reading 1,637 heap blocks until one
VACUUM sets the visibility map; then heap fetches drop to zero.
-
Ch. 4 — LIKE Reads Every Row; an Inverted Index Reads Five Buffers
— finding a word with
ILIKE '%…%' scans 5M rows (~1.25 s); a tsvector+GIN index does it in ~19 ms, the probe touching 5 buffers — ~65× faster.
-
Ch. 4 — Storing 230 MB Wrote 2 GB to Disk
— an LSM (RocksDB) writes 2,091 MB to durably store 230 MB — a 9× write amplification, ~7× of it compaction — while the database ends up just 235 MB.
Source: github.com/atharh/study · each exercise's .md is the source of truth; the .html is its rendered companion.