A tree built for slow storage
A red-black tree is optimised to minimise comparisons in RAM. A B-tree (Bayer and McCreight, 1972) is optimised for something else entirely: minimising the number of disk reads, which are vastly slower than any in-memory comparison. Instead of one key per node, a B-tree of order m packs many keys into each node — enough to fill exactly one disk page or cache line — so a single slow read pulls in hundreds of comparisons' worth of information at once.
order m B-tree, every non-root node holds: between ceil(m/2) - 1 and m - 1 keys between ceil(m/2) and m children (internal nodes) keys inside a node are sorted; the k+1 children of a node with k keys "straddle" the k keys, so child[i] holds keys strictly between key[i-1] and key[i]
Insertion: fill, split at the median, push up
A new key is inserted into the appropriate leaf, keeping it sorted. If that leaf now holds m keys — one too many — it splits: the median key moves up into the parent, and the keys on either side of it become two separate half-full nodes.
insert(key):
leaf = find_leaf(key)
insert key into leaf, keeping it sorted
while leaf.keyCount == m: // overfull, must split
mid = leaf.keys[m / 2] // median key
left, right = split leaf around mid
if leaf has no parent:
create new root with mid, children [left, right] // tree grows +1 level
else:
insert mid into leaf.parent, replace leaf with [left, right]
leaf = leaf.parent // the split may cascade upward
The crucial detail is that a B-tree only grows upward, by splitting the root, so every leaf always stays at the exact same depth — there is no leaf that is deeper than another, unlike an unbalanced binary tree.
Why the height barely counts as logarithmic
A B-tree's height is O(log_m n), where the base of the logarithm is the branching factor m, not 2. A red-black tree with a million keys has a height around 2·log2(1,000,000) ≈ 40. A B-tree of order 200 storing the same million keys has a height around log_200(1,000,000) ≈ 2.6 — practically 3 levels. That difference is the entire reason B-trees exist: with a large enough m chosen to match a disk page or cache line, essentially any database table with millions or billions of rows can be searched in 3 or 4 disk reads, and the top one or two levels typically stay cached in RAM permanently, making most lookups even cheaper in practice.
B+ trees and B* trees
Almost no production database uses a plain B-tree; nearly all use a B+ tree. The difference: internal nodes in a B+ tree store copies of keys purely to route searches, while all the actual data lives in the leaves, and the leaves are linked into a chain. That chain turns an ordered range query — "give me every row between X and Y" — into a single tree descent followed by a fast sideways walk along linked leaves, instead of repeated full tree traversals. A B* tree goes further and delays splitting: when a node overflows, it first tries to redistribute keys with a sibling, splitting into two only when both neighbours are also full, and splits 2 full nodes into 3 two-thirds-full ones instead of 2 half-full ones — keeping nodes fuller (about 2/3 instead of 1/2) at the cost of a more complex insert.
Frequently asked questions
Why do databases use B-trees instead of a red-black tree?
A red-black tree has one key per node and reads one node from disk per comparison, which for a million-row table means roughly 20 slow disk seeks per lookup. A B-tree packs hundreds of keys into each node, sized to match a disk page, so each disk read compares against hundreds of keys at once. The same million rows need only 3 or 4 disk reads, because the tree's branching factor — not its key count — determines the height.
What is the difference between a B-tree and a B+ tree?
In a plain B-tree, keys and their associated data live in both internal nodes and leaves. In a B+ tree, all data lives only in the leaves, internal nodes store copies of keys purely for routing, and the leaves are linked together in a chain. That leaf chain lets a B+ tree do a fast ordered range scan by walking sideways instead of re-traversing the tree, which is why almost every production database index is a B+ tree rather than a classic B-tree.
Why must every leaf be at the same depth?
It is the property that gives a B-tree its guaranteed O(log n) search: every lookup walks exactly height-many nodes regardless of which key it is looking for. A B-tree keeps this true by growing upward — a new level is only added when the root itself splits — rather than growing downward and leaving some leaves deeper than others.
Try it live
Everything above runs in your browser — open B-Trees and change the parameters while it is running. Nothing is installed, nothing is uploaded, the whole model lives in one tab.
▶ Open B-Trees simulation