When it does not fit

The sibling a full leaf asks first

The rule databases use to fix ascending inserts fills their leaves completely and collapses to 53.4% when one key in a hundred arrives late. A leaf that offers a key to a sibling before it splits, and splits two full leaves into three when neither will take one, holds 84.2% on the same stream — and is better with a trickle of late keys than without one, because a perfectly ascending stream has no sibling with room.

The keys that arrive late measured how full a B±tree’s leaves end up, and found the answer is decided by the order the keys arrived in. Inserted at random, the leaves end 70.5% full — the classical ln2\ln 2. Ascending, 51.6%. Descending, 50.0%. The rule real databases use for ascending inserts, splitting a full leaf at its right-hand end rather than down the middle, fills ascending leaves completely and does nothing at all for descending ones.

And it is brittle. Let one key in a hundred arrive late in an otherwise ascending stream and the rightmost rule’s leaves fall from 100% to 53.4% — worse than even splits on the same stream.

The damage comes from one event: a full leaf split into two halves that will never be refilled. The classical answer is to avoid producing half-full nodes at all. A B*-tree asks a sibling first: when a leaf overflows, push a key into a neighbour that has room, and only when both neighbours are full split the two of them into three, each about two-thirds full. This page builds that and measures it on the same streams.

What it does to a trickle of disorder

Late arrivals in an ascending stream: with 1% of keys late the rightmost rule's leaves are 53% full and redistribution's 84%, with 50% late 68% and 84%A B+-tree of 131,072 keys arriving in ascending order except for a share that arrive at a random later point, under 3 split rules. 0% late: even splits 51.6%, rightmost-split rule 100.0%, sibling first, two into three 67.2%. 1% late: even splits 52.1%, rightmost-split rule 53.4%, sibling first, two into three 84.2%. 2% late: even splits 52.6%, rightmost-split rule 52.9%, sibling first, two into three 81.4%. 5% late: even splits 53.8%, rightmost-split rule 53.3%, sibling first, two into three 79.0%. 10% late: even splits 55.8%, rightmost-split rule 54.7%, sibling first, two into three 79.5%. 25% late: even splits 62.1%, rightmost-split rule 60.5%, sibling first, two into three 83.1%. 50% late: even splits 69.1%, rightmost-split rule 67.5%, sibling first, two into three 84.4%.50%60%70%80%90%100%0%1%2%5%10%25%50%share of keys arriving latemean leaf filleven splitsrightmost-split rulesibling first, two into threeln 2131,072 keys, leaves of 64late keys arrive at a random later point
Fig. 1 Mean leaf fill of a B±tree of 131,072 keys arriving in ascending order except for a share that arrive at a random later point, under three split rules. With no late keys: even splits 51.6%, the rightmost rule 100.0%, redistribution 67.2%. With 1% late: 52.1%, 53.4% and 84.2%. With 5% late: 53.8%, 53.3% and 79.0%. With 50% late: 69.1%, 67.5% and 84.4%.

The two lines cross at the first per cent, and they never cross back.

With one key in a hundred arriving late, redistribution holds 84.2% where the rightmost rule holds 53.4% — a tree of 2,437 leaves against 3,838, which is 36% less index to read, write and cache. The improvement is not marginal and it is not at a corner of the parameter space; a trickle of disorder is the ordinary condition of an index on a table with a serial key and any updates at all.

And the shape of the redistribution line is the finding worth carrying. It is lowest at zero late keys — 67.2%, worse than the rightmost rule’s 100% — and jumps to 84.2% as soon as one key in a hundred is out of order. The rule that repairs late arrivals is better with late arrivals than without them.

That reads like a mistake and is not. On a perfectly ascending stream every insertion goes to the rightmost leaf, and that leaf’s left sibling is full while its right sibling does not exist. There is nothing to redistribute into, so every overflow is a two-into-three split, which leaves nodes two-thirds full and nothing better. A trickle of late keys lands in leaves all over the tree, and those leaves have siblings with room; a redistribution then fills a sibling rather than making a new node, which is precisely what the rightmost rule cannot do, because the sibling it would have to write to is not the one it is splitting.

The three orders

The same 131,072 keys in 10 trees: leaves from 50% to 100% full, and 2,048 to 4,095 leavesA B+-tree with leaves of 64 keys and 64 children to a node, holding 131,072 keys, built by inserting them in 3 orders under 3 split rules, and bulk-loaded from sorted keys. Each bar is the mean leaf fill. random, even splits: 70.5% full, 2,906 leaves, height 3. random, rightmost-split rule: 69.4% full, 2,949 leaves, height 3. random, sibling first, two into three: 84.3% full, 2,429 leaves, height 3. ascending, even splits: 51.6% full, 3,971 leaves, height 4. ascending, rightmost-split rule: 100.0% full, 2,048 leaves, height 3. ascending, sibling first, two into three: 67.2% full, 3,048 leaves, height 4. descending, even splits: 50.0% full, 4,095 leaves, height 4. descending, rightmost-split rule: 50.0% full, 4,095 leaves, height 4. descending, sibling first, two into three: 67.2% full, 3,048 leaves, height 4. bulk-loaded from sorted keys: 100.0% full, 2,048 leaves, height 3.0%25%50%75%100%ln 2mean leaf fillrandom, even splits2,906 leavesrandom, rightmost-split rule2,949 leavesrandom, sibling first, two into three2,429 leavesascending, even splits3,971 leavesascending, rightmost-split rule2,048 leavesascending, sibling first, two into three3,048 leavesdescending, even splits4,095 leavesdescending, rightmost-split rule4,095 leavesdescending, sibling first, two into three3,048 leavesbulk-loaded from sorted keys2,048 leaves131,072 keys, leaves of 64each bar names its rule
Fig. 2 The same 131,072 keys in ten trees: three arrival orders under three split rules, and bulk-loaded from sorted keys. Random: 70.5% with even splits, 69.4% with the rightmost rule, 84.3% with redistribution — 2,906, 2,949 and 2,429 leaves. Ascending: 51.6%, 100.0%, 67.2%. Descending: 50.0%, 50.0%, 67.2%.

Read down the redistribution column and the rule’s character is plain. It is the only one of the three that never falls below two thirds on any order, and the only one that treats ascending and descending alike — 67.2% for both, to a tenth of a per cent, because neither has a sibling with room and both therefore go through the same two-into-three split every time.

It is also the only rule that beats ln2\ln 2 on random insertions, and by a wide margin: 84.3% against 70.5%. Random insertion is the case the rightmost rule was never about, and it is the case most of an index’s life is spent in.

The classical analysis puts a B*-tree’s random-insertion limit at about 81% against ln2\ln 2 for plain splits. This measures 84.3%, above that, and the reason is a difference in the rule rather than in the arithmetic: the classical rule redistributes only when a split would otherwise happen and moves enough keys to balance the two nodes, while this one pushes a single key into whichever sibling has room and only balances when it must. Moving one key is the smallest repair that fixes the overflow, so it defers splits longer.

2,429 leaves from 131,072 random insertions: every one between 43 and 64 keys full of 64, mean 84.3%The number of keys in every leaf of a B+-tree with leaves of 64 keys, built by inserting 131,072 keys in random order with the rightmost-split rule. A leaf that overflows splits into two holding about half each, so no leaf holds fewer than 32 or more than 64. The leaves hold between 43 and 64 keys, mean 54.0, which is 84.3% full; ln 2 is 69.3%. 669 leaves hold fewer than 48 keys and 1,760 hold 48 or more.016324864keys in the leaf, of 64leavesmean 54.0131,072 keys, random orderrightmost-split rule
Fig. 3 Every leaf of the random-insertion tree under redistribution: 2,429 leaves holding between 43 and 64 keys of 64, mean 54.0. Compare the same tree under even splits, whose leaves run from 32 to 64 and average 45.1: 61% of its leaves are under three-quarters full, against 28% of this one’s.

The difference between the two histograms is where the rule’s gain lives, and it is not where a reader would expect. Redistribution does not make the full leaves fuller — both distributions reach 64 — it removes the empty half of the range. The even-split tree’s leaves start at 32 because a split produces two halves of a full node; redistribution’s start at 43 because the only thing that ever produces a new leaf is a two-into-three split, and three nodes from 129 keys is 43 each. The floor moved and the ceiling did not, and the mean moved with the floor: 32 to 43 at the bottom, 45.1 to 54.0 in the mean, 64 at the top either way.

That is also why the classical 81% and this 84.3% are both right. A rule that splits two into three has a hard floor of two-thirds; how far above it the mean sits depends on how long redistribution defers the next split, and moving one key at a time defers it longest. The floor is the theorem and the mean is the implementation.

3,048 leaves from 131,072 descending insertions: every one between 43 and 51 keys full of 64, mean 67.2%The number of keys in every leaf of a B+-tree with leaves of 64 keys, built by inserting 131,072 keys in descending order with the rightmost-split rule. A leaf that overflows splits into two holding about half each, so no leaf holds fewer than 32 or more than 64. The leaves hold between 43 and 51 keys, mean 43.0, which is 67.2% full; ln 2 is 69.3%. 3,047 leaves hold fewer than 48 keys and 1 hold 48 or more.016324864keys in the leaf, of 64leavesmean 43.0131,072 keys, descending orderrightmost-split rule
Fig. 4 Every leaf of the descending-order tree under redistribution: 3,048 leaves holding between 43 and 51 keys of 64, mean 43.0. The two-into-three split is what produces that band — three nodes from two full ones is 2/3 of 64 each, and the spread either side of it is the one key at a time that redistribution moves before the split happens.

That histogram is the rule’s signature and is worth setting against the even-split rule’s, which spreads from 32 to 64. A rule that splits two nodes into three has a much narrower distribution of fills than one that splits one into two, because it starts from more keys, and a narrower distribution is worth something on its own: an index whose leaves are all within eight keys of each other has a predictable size, and one whose leaves run from half to full does not.

The two orders that cannot redistribute

Ascending and descending insertion both give 67.2% under redistribution, to a tenth of a per cent, on trees of 3,048 leaves and 3,046 two-into-three splits each. Two arrival orders that no other rule treats alike produce, under this one, the same tree.

The reason is that redistribution is unavailable to both. On an ascending stream the overflowing leaf is always the rightmost, whose left sibling is full and whose right sibling does not exist. On a descending stream it is always the leftmost, with the mirror problem. Every overflow is therefore a two-into-three split, and a tree built entirely from two-into-three splits sits at the floor.

So the rule’s symmetry between ascending and descending is the symmetry of its failure, not of its success — which is worth knowing, because the rightmost-split rule’s asymmetry (100% ascending, 50% descending) is usually described as the thing to fix, and fixing it by making both 67.2% is only half of what the plate on late arrivals shows. The whole of it is that a stream with any disorder at all lets redistribution work, and 1% of keys out of order takes it from 67.2% to 84.2% while taking the rightmost rule from 100% to 53.4%.

2,433 leaves from 131,072 late1 insertions: every one between 43 and 64 keys full of 64, mean 84.2%The number of keys in every leaf of a B+-tree with leaves of 64 keys, built by inserting 131,072 keys in late1 order with the rightmost-split rule. A leaf that overflows splits into two holding about half each, so no leaf holds fewer than 32 or more than 64. The leaves hold between 43 and 64 keys, mean 53.9, which is 84.2% full; ln 2 is 69.3%. 1,189 leaves hold fewer than 48 keys and 1,244 hold 48 or more.016324864keys in the leaf, of 64leavesmean 53.9131,072 keys, late1 orderrightmost-split rule
Fig. 5 Every leaf of the tree built from an ascending stream with one key in a hundred arriving late, under redistribution: 2,433 leaves between 43 and 64 keys full, mean 53.9 — within four leaves and a tenth of a key of the random-insertion tree. A trickle of disorder is enough to put the rule in the regime it is good at.

Four leaves and a tenth of a key separate that tree from the random-insertion one. A rule whose result is indistinguishable between a nearly-sorted stream and a shuffled one has removed the arrival order from the answer, which is precisely what the rightmost rule failed to do and what the keys that arrive late set out as the problem.

What it costs

Nothing about this is free, and the currency is the one the writes nobody counted is about.

An even split writes one new node and rewrites one. A redistribution writes two nodes — the overflowing leaf and the sibling — and updates a separator in the parent. A two-into-three split writes three nodes and inserts a separator. Counted as keys moved between leaves, on 131,072 keys:

  • random: 190,241 moves, 1.45 a key, from 34,809 redistributions and 2,427 two-into-three splits;
  • ascending: 261,966 moves, 2.00 a key, from 63,976 redistributions and 3,046 splits;
  • one per cent late: 234,102 moves, 1.79 a key, from 77,914 redistributions and 2,435 splits.

So the rule costs about one and a half to two extra key movements per key inserted, against a plain split’s amortised one movement per key. Roughly double the write traffic during building, for between 20% and 60% fewer leaves afterwards.

Whether that is a good trade depends on the ratio of insertions to queries over the index’s life, and it is the same shape of trade one dial between two structures drew between a B-tree and a log-structured store: write amplification against read cost, with the crossing decided by the workload rather than by the structure. An index built once and read for months should redistribute. An index rewritten as fast as it is read should not, and should probably not be a B-tree.

The separator updates are the part of the cost that is easy to forget and hard to avoid. Every redistribution moves a key across a boundary between two leaves, so the parent’s separator for that boundary is now wrong and has to be rewritten — 34,809 of them on the random stream, 77,914 on the stream with one per cent late. A separator update is small, the parent is certainly in memory, and a structure that got it wrong would still hold every key and would no longer be able to find them. So every tree on this page is verified by reading its leaves left to right and requiring them to come out sorted, and by requiring every separator to equal the first key of the subtree it stands in front of — rather than by counting the keys and calling that correct, which a tree with a stale separator would pass.

There is one asymmetry worth naming in the rule’s favour. The moves are writes to nodes that are already in memory — a redistribution touches the overflowing leaf, which was just written to, and one sibling, which the parent points at. A plain split allocates a new node somewhere else. So counting key movements overstates the difference in transfers, and this page does not count transfers.

The rule read as an amortisation

There is a way of stating what redistribution does that makes both its gain and its cost obvious, and it is the way what amortised means states a dynamic array’s doubling.

A plain split is a structure that pays nothing until it pays a lot: every insertion is one write, until the one that overflows a leaf and writes two nodes. The cost is small and even, and the fill is what the evenness buys — a leaf that has just split is half empty and will stay half empty if nothing else arrives near it.

Redistribution moves work forward. It pays a little on many insertions — 34,809 redistributions over 131,072 random keys, so about one insertion in four moves a key to a sibling — in order to pay the large cost less often: 2,427 two-into-three splits against the plain rule’s 2,905 splits. The amortised write cost goes up by about half and the number of nodes goes down by a sixth.

That framing says what to watch for, which is the tail rather than the mean. A redistribution is a write to a node the parent already points at; a chain of them is not possible here because only one key moves and only into an adjacent sibling. So the worst insertion under this rule writes three nodes — the two-into-three split — where the worst under a plain split writes two, and no insertion is worse than that. The rule raises the mean cost and barely moves the worst, which is the opposite of the usual amortisation complaint and is worth having.

Why the height is the other half

Leaves against keys: ascending insertion needs 1.94 times the leaves of a bulk-loaded tree at 262,144 keys, and an extra level from 4,096Leaves in a B+-tree with leaves of 64 and 64 children to a node, against the number of keys, on logarithmic axes, for insertion in random and ascending order with even splits and for a tree bulk-loaded from sorted keys. random: 94 leaves at 4,096, 185 leaves at 8,192, 372 leaves at 16,384, 736 leaves at 32,768, 1,462 leaves at 65,536, 2,906 leaves at 131,072, 5,851 leaves at 262,144; heights 3, 3, 3, 3, 3, 3, 4. ascending: 124 leaves at 4,096, 248 leaves at 8,192, 496 leaves at 16,384, 993 leaves at 32,768, 1,985 leaves at 65,536, 3,971 leaves at 131,072, 7,943 leaves at 262,144; heights 3, 3, 3, 3, 3, 4, 4. Bulk-loaded: 64 at 4,096, 128 at 8,192, 256 at 16,384, 512 at 32,768, 1,024 at 65,536, 2,048 at 131,072, 4,096 at 262,144; heights 2, 3, 3, 3, 3, 3, 3.4,09616,38465,536262,14410010³keysleavesrandom · height 4ascending · height 4bulk-loaded · height 3leaves of 64, 64 children to a nodeeven splits
Fig. 6 Leaves against keys held, for random and ascending insertion with even splits, and for a tree bulk-loaded from sorted keys, on logarithmic axes. The gap between the measured curves and the bulk-loaded one is the index a split rule leaves behind, and where the curves cross a power of the fan-out the tree gains a level the bulk-loaded tree does not need.

The fill numbers on the first two plates carry a consequence the bars do not show. A tree of 2,429 leaves and a tree of 3,971 leaves are not merely different sizes; at a fan-out of 64 they can be different heights, and a height is a transfer on every query.

At 131,072 keys the redistribution tree on random insertions is 2,429 leaves and three levels; the even-split tree on ascending insertions is 3,971 leaves and four. Every point lookup on the second pays one more transfer than every lookup on the first, for the whole life of the index, because of the order the keys happened to arrive in and the rule that responded to it. A tree with nodes the size of a block measured a B-tree’s height as the whole of its query cost; this is that cost being set by an insertion rule.

What is not measured here

Redistribution at the leaves only. The internal levels keep the ordinary even split. The leaves hold the keys and are what the fill measures, and mixing two rules at two levels would make the measurement about the mixture. A full B*-tree redistributes everywhere, which would raise the fan-out of the internal nodes and occasionally remove a level; nothing here bounds that.

One key at a time. A leaf pushes one key into a sibling, which is the smallest repair. The classical rule moves enough to balance the two, which produces a different fill distribution and more moves per redistribution. Which of the two is better is a sweep this page does not run.

Left before right. A leaf asks its left sibling first and its right second. On an ascending stream that is the worse order — the left sibling is the one just filled — and on a random stream it makes no difference the measurement can see. The choice is arbitrary and it is not swept.

No deletions. Every tree here is built by insertion and never shrinks. A B*-tree’s merging rule on deletion is the mirror of its splitting rule and has its own fill floor, and the promise that does not survive the tree is the general warning that a structure’s guarantees under one operation are not its guarantees under another.

Keys moved, not transfers. The cost above is keys moved between leaves. A transfer model would charge per block touched, would forgive the moves that stay inside a node already fetched, and would charge the parent’s separator update that this count ignores.

Building, not maintaining. Every measurement is of a tree built from empty. An index that has been running for a year is not the tree its arrival order built; it is that tree after deletions, page splits from updates and whatever the storage engine did to it. What the generated collection was right about is the standing caution about measuring an instrument rather than a subject, and a freshly built tree is an instrument.

One fan-out. Leaves of 64 keys and 64 children a node throughout. The two-into-three split’s 2/3 floor is independent of the fan-out; the redistribution’s effect on the fill is not obviously so, since a wider leaf has more room to absorb a pushed key before it too overflows.

Still open: asking a sibling that is not adjacent

The rule here asks the two leaves either side of the overflowing one, which are the two the parent can reach without descending anywhere else. A leaf at the edge of its parent’s children has only one such sibling, and a leaf that is an only child has none — which is why the ascending stream’s redistributions do so little.

There is a wider version. The parent knows all its children, and a leaf overflowing in a parent with sixty-four children has up to sixty-three candidates with room, all of them reachable without leaving the node. Moving a key two positions along requires moving a key at every position between, which is a chain of single moves and a separator update for each — expensive per repair, and it defers a split much longer.

The measurement that follows implements the chain: on overflow, walk outwards from the leaf until a sibling with room is found, and shift one key along each step of the way. It asks how far a chain typically has to walk on each of the four arrival orders, how much further the fill rises above 84.3%, and where the extra moves overtake the leaves they save — which is the same crossing this page drew between 1.45 moves a key and 36% fewer leaves, at a different point on the same curve.

What this makes readable

Essays that name this one as a prerequisite.

Named alongside this one

Essays reaching for the same objects. Nobody chose these; they are what the concept index makes visible.

What links here

Every essay whose body links to this one.

The objects this essay names

Each one links to every other essay that touches it.

AmortisationB-treeBlock sizeBulk loadingDesign parameterIndex maintenanceInsertion orderNode fillPresortednessSpace time tradeWorst case