What distinguishes a B+tree from a classic B-tree, and why do relational storage engines almost always choose the B+tree variant for table indexes?
answer
- B-tree: payload in every node, early exit possible
- B+tree: payload only in leaves, always full descent
- Separators can be abbreviated/synthetic
- Linked leaves = one sorted sequence
- Skinny branch entries → higher fanout → shallower
basics
~20 sIn a classic B-tree, payload lives in every node; in a B+tree, only leaves carry keys with row pointers and internal nodes hold pure separators. That keeps branch entries tiny, so fanout is higher and the tree shallower, and all data sits in one sorted, linked leaf level.
solid answer
~60 sTwo structural differences: 1. **Where payload lives.** A classic B-tree stores a key *and its associated value/pointer* in every node, including internal ones, so a search can terminate early at any level. A B+tree stores payload only in leaves; internal nodes hold nothing but separator keys and child pointers, and every search always descends to a leaf. 2. **Leaf linkage.** B+tree leaves form a sorted linked list; B-tree nodes generally do not. Why engines pick B+tree: internal entries become as small as possible, so more of them fit per page, so fanout is higher and the tree shallower — fewer page reads per lookup. Also, because the entire key set lives in one contiguous, sorted, linked leaf level, ordered traversal is a leaf walk rather than an in-order tree traversal that keeps bouncing between levels. The cost is that a B+tree never short-circuits: even a key that happens to be a separator must be followed all the way to a leaf. In practice that is a rounding error against the fanout win.
go deeper
Know the one-line difference: B+tree keeps data only in leaves and links them; classic B-tree keeps data in every node.
Explain the consequence — skinnier branch entries mean higher fanout, shallower trees, fewer page reads, and one sorted leaf level.
Add the operational angle: branch levels are under 1% of the index and stay cached, and leaf-only payload simplifies split, merge and concurrency handling.
Frame it as an I/O-cost optimization and note where the assumption changes — in-memory or write-optimized engines make different node-layout choices.
## The two structures side by side Both are balanced, multi-way, page-oriented search trees. The difference is what the nodes hold. **Classic B-tree.** Each node holds a sorted run of *(key, payload)* pairs interleaved with child pointers. The payload might be the row itself or a row pointer. A search compares against keys as it descends and can stop the moment it finds the key — possibly at the root. **B+tree.** Internal nodes hold only *separator keys* and *child pointers*; no payload at all. Every key that exists in the index also appears in a leaf, together with its row pointer. A search therefore always descends the full height, even if the search key matches a separator on the way down. Leaves are chained left-to-right (often doubly), forming a sorted list of the entire key space. A separator in a B+tree does not even need to be a real key value — it only has to divide the key space — so engines can store abbreviated or synthetic separators (for example, the shortest byte prefix that distinguishes two subtrees). ## Why B+tree wins on disk **Higher fanout, shallower tree.** Node size is fixed at one page. If each internal entry must also carry payload, fewer entries fit, so the branching factor drops and the tree grows taller. Since the dominant cost of a lookup is the number of pages touched, anything that raises fanout is the single most valuable optimization available. Stripping payload out of the internal levels is exactly that. **Predictable cost.** Every lookup costs the same number of page accesses because every lookup ends at a leaf. This uniformity makes the optimizer's cost model simple and makes latency stable, which operationally matters more than an occasional lucky early hit at an upper level. **One sorted level for everything.** All keys are in the leaf level, in order, with sibling links. That makes ordered access a linear walk over leaves. In a classic B-tree the sorted sequence is spread across all levels, so ordered traversal is a full in-order walk that continually re-visits internal nodes — far more random and far more page touches. **Tiny, cacheable branch structure.** With payload removed, the internal levels together are roughly `1/fanout` of the index size — well under one percent. Those pages stay pinned in the buffer pool in practice, so the top of the descent costs no I/O at all and only the leaf access tends to be physical. **Uniform maintenance.** Because payload only ever moves between leaves, splits and merges have simpler invariants: the internal levels only ever gain or lose separators. In a B-tree, splitting a node that carries payload means relocating payload upward, which complicates concurrency control and recovery. ## What the B+tree gives up The honest tradeoff is the lost early exit. In a B-tree, a small fraction of lookups terminate above the leaf level. But that fraction is roughly the share of keys stored above the leaves, which for high fanout is under one percent — and those top pages are cached anyway, so the saved access is usually a memory hit, not a disk read. Trading a sub-1% early-exit chance for a several-fold increase in fanout is not a close call. Some engines also blur the line: a B+tree variant may store the row itself in the leaf (an index-organized or clustered table) rather than a pointer, which is a decision about leaf payload, not about the B-tree/B+tree distinction. ## How to phrase it in an interview "Classic B-tree: keys and payload in every node, search can stop early. B+tree: payload only in leaves, internal nodes are pure separators, leaves are linked in sorted order. Engines choose B+tree because removing payload from the branch levels maximizes fanout and therefore minimizes tree height and page reads, keeps the entire branch structure small enough to stay cached, and puts every key in one sorted linked level so ordered access is a leaf walk." ## Naming caveat In everyday speech, "B-tree index" almost always means a B+tree — engine documentation and even index-type names use "btree" loosely. If an interviewer asks the difference, they are testing whether you know the distinction exists, not trying to catch you out on vocabulary. Say the distinction, then note that the common term refers to the B+tree variant.
- Doesn't always descending to a leaf make a B+tree slower than a B-tree?Only for the small share of lookups that would have terminated at an upper level, which is roughly the fraction of keys stored above the leaves — under one percent at realistic fanout. Those upper pages are almost always resident in memory anyway, so the saved access would have been a cache hit, not a disk read. Meanwhile the higher fanout removes whole levels for every lookup, so the net effect is strongly positive.
- Why can a B+tree separator be a value that does not exist in the table?Its only job is to say which subtree a search key belongs to, so any boundary that partitions correctly works. Engines exploit this with prefix truncation — storing just enough leading bytes of a string to distinguish the subtrees. Shorter separators mean more entries per branch page and therefore higher fanout.
saying these in an interview costs you the question
- Claiming both variants store data in leaves only, so there is no real difference
- Saying B+tree is chosen because it is balanced — both variants are balanced
- Asserting a B+tree can end a search at an internal node
- Believing leaf sibling links exist in classic B-trees too
- Treating the naming ('btree index') as proof the engine uses a classic B-tree