Books Deep-Read · DDIA · Chapter 3

Storage and Retrieval

Designing Data-Intensive Applications · Ch 3 · Martin Kleppmann · 2017

中文 →

What is this chapter about?

Every order you place, every message you send, eventually has to land on some spot on a disk—and the next time you look, it has to be found again, fast. That's the whole job of a database's guts: put data down, get it back. Chapter 3 lifts the lid and shows you two very different ways to store data, and why the database "people use" and the database "analysts use" are, deep down, not the same animal at all.

An analogy first

Think of a database as a bookkeeper with two styles. The running-ledger style: every transaction just gets appended to the end of the notebook, never going back to edit old entries; when a little notebook fills up, it's copied out into a big ledger that's sorted alphabetically, and at night several old ledgers get merged and tidied. The ring-binder style: an alphabetically-tabbed binder where, to change an entry, you flip to that page and erase-and-rewrite it. Both work, but they have opposite temperaments—one writes blazingly fast, the other finds things rock-steady.

The dumbest database, and the price of an "index"

The laziest way to store data is the running ledger: append each record to the end of a file—writing is lightning fast. But to find one record you must scan from the top; with lots of data that's a disaster. So you build an index: like the index at the back of a book, it lets you "jump straight to the page for this name." But there's no free lunch: an extra index makes reads faster, yet every write now has to update the index too, so writes get slower. That's why a database won't index everything for you—you have to choose.

The two temperaments

The running-ledger family (databases call it LSM) writes blazingly fast because it only ever appends and never turns back to edit; the price is that finding a record may mean flipping through several ledgers, and while it merges old ledgers in the background it occasionally competes with your normal reads and writes for the disk, making the odd request stall. The ring-binder family (the famous B-tree) finds things steadily, edits cleanly, and keeps each record in exactly one slot; the price is that a write means flipping back to erase-and-rewrite in place, and every page leaves a little blank space—some waste. Facebook once switched its social data from ring-binder to running-ledger and cut disk usage by more than sixty percent.

Analytics data wants to be stored "sideways"

Normally a database stores data "one person, one whole row": looking up everything about you is fast, it's all in one place. But when the boss wants "the average age of all users," the system has to flip through hundreds of millions of rows and use only the "age" field from each—reading a mountain of stuff it doesn't need. So databases built for analytics do the opposite—store by column, sideways: everyone's "age" piled together, everyone's "city" piled together. Averaging reads only the age pile; and because one column looks alike (all ages are numbers), it compresses down tiny. That's why companies build a separate "data warehouse" for reports instead of running them on the database you use every day.

Remember this one line

A database stores data in one of two families: the running ledger (writes fast, merges in the background) and the ring binder (reads steady, edits in place); then look at purpose—store by row for people, by column for analytics. Pick the right guts and the same query can run tens of times faster.

Want the actual mechanisms, structure diagrams and real systems? → switch to Deep mode