Visual walkthrough — Indexing — B-tree index, hash index, full-text
This is the visual companion to the parent note. It leans on the ideas of Disk vs Memory I/O, B+ Tree Data Structure, and Big-O Notation — we rebuild each one from zero here.
Step 1 — What a "row lookup" actually costs
WHAT. Picture a table as a stack of boxes on a shelf. Each box is one row (one record, e.g. one user). We want the box where email = 'x'.
WHY start here. Before we can say an index is fast, we must feel how slow the no-index way is. The unit we care about is not "seconds of thinking" — it is a disk read: fetching one chunk of data off the disk. Read Disk vs Memory I/O — a disk read is thousands of times slower than a CPU comparison, so we count disk reads, and only disk reads.
PICTURE. In the figure, boxes are lined up left-to-right. To find our target we must open box 1, check, open box 2, check... every single box until we hit it. That is a full table scan.

Step 2 — The core trick: a signpost that skips boxes
WHAT. Instead of opening every box, we add signposts. A signpost is a small note that says: "boxes with keys below 30 are to the left; 30 and above, to the right."
WHY this specific trick. One signpost, read once, lets us throw away half the shelf without opening those boxes. That is the entire idea of a search tree: each read we make must eliminate many boxes, not just one. A B+ Tree Data Structure is a tree of these signposts.
PICTURE. The figure shows one signpost holding the separator key . An arrow to the left is labelled "keys ", an arrow to the right "keys ". Following the correct arrow, we ignore the whole other side.

If each signpost only had 2 arrows, we'd halve the work each read. But disk pages let us do far better — that is Step 3.
Step 3 — Why nodes are FAT: the branching factor
WHAT. A disk read never fetches one byte — it fetches a whole page (~8 kilobytes). So a node might as well hold hundreds of separator keys and hundreds of arrows, all read in that one page.
WHY it matters enormously. More arrows per node = fewer levels to fall through = fewer disk reads. We give this "arrows per node" number a name.
PICTURE. The figure contrasts two nodes read with one disk read each: a skinny node with 2 arrows, and a fat node with (here) 4 arrows. The fat node splits the shelf into 4 pieces at once, not 2.

Step 4 — Stacking levels: how many boxes can reads reach?
WHAT. Now stack the fat nodes into levels. The root is level . Its arrows point to nodes on level . Each of those has arrows to level , and so on. We count how many leaf boxes are reachable after levels.
WHY multiply. Every level multiplies the reach by , because each node at the current level fans out into new ones. Multiplication is exactly "repeated fanning-out", so the reachable count grows like a power of .
PICTURE. The figure is a small tree, . Level 0: 1 root. Level 1: nodes. Level 2: leaves. Each level's count is annotated as a power of 3.

Step 5 — Solving for the height (the central result)
WHAT. We have rows to store in the leaves. We need enough leaves, so we require . Solve this for .
WHY the logarithm appears. is exponential growth in . To undo an exponential — to ask "what power turns into ?" — the exact tool is the logarithm. That is what a log is: the inverse of a power. No other tool answers "which exponent?".
PICTURE. The figure plots (orange, exploding upward) against the flat target line (blue). The height we need is the where the orange curve first crosses the blue line — and the log is just the horizontal coordinate of that crossing.

Step 6 — Plug in a billion and watch it collapse
WHAT. Take (a billion rows) and . Compute .
WHY these numbers. They are realistic: web-scale tables reach billions of rows, and a page of keys easily fans out ~100 ways. This is the moment the abstraction pays off.
PICTURE. A bar chart: a full scan bar towering at reads next to a B-tree bar at height — so tiny it is barely visible. Same table, same query.

Step 7 — The degenerate case: what if ?
WHAT. Push the formula to its breaking point. Suppose each node had only one child () — a "tree" that is really a single chain.
WHY test this. A good derivation must survive its extremes. If the tree should behave like the full scan we started with — let's verify the formula agrees, so we trust it everywhere in between.
PICTURE. The figure shows the fat tree degenerating into a vertical rope of nodes — one long line, no fan-out. Below it, the formula's output blows up.

The one-picture summary
This final figure compresses all seven steps: a fat, shallow B-tree over leaves, , with the descent path highlighted — root → level 1 → ... → leaf, exactly hops — beside the exploding full-scan alternative. Every arrow you follow is one disk read; five arrows reach any of a billion rows.

Recall Feynman: the whole walkthrough in plain words
Finding one row by reading every box costs reads — hopeless for a billion boxes. So we lay down signposts that each throw away a big chunk of the shelf. Because a disk read grabs a whole page, one signpost can point == ways at once== (its branching factor). Stack these signposts into levels: each level multiplies your reach by , so after levels you can reach boxes. To cover all boxes you need ; asking "what power of is ?" is the definition of a logarithm, giving . Plug in a billion rows and : that's reads. If were the tree becomes a useless rope and the log blows up — which is precisely why nodes are kept fat and the tree kept balanced. Five reads for a billion rows. That is the entire magic of the B-tree.
Recall Quick self-check
Why is the lookup cost and not ? ::: We read exactly one node (one page) per level as we descend, and there are levels; only affects how shallow those levels are. What tool undoes to isolate , and why? ::: The logarithm , because a log is by definition the inverse of a power — it answers "which exponent?". What happens to as ? ::: It diverges (infinite/undefined); the tree degenerates into an chain, so databases keep large and the tree balanced.