B-Trees and B+ Trees

A billion keys.
How many disk reads?

Start with the lecture’s problem: a balanced tree can still make too many trips to disk. Follow the index, split a full node, then discover why B+ leaves stay linked.

0 of 6 quick checks explored
Explore as you readChange a value, predict an answer, and use Step to follow the tree. Teal arrows are child pointers; purple arrows are leaf links. Enlarge keeps small labels readable.

14.1From binary trees to m-way search trees

Balance controls the path length. What if every step costs a disk read?

TRY THE LECTURE’S BIG IDEA

Pack more keys into each page

Binary · m = 230levels / uncached path reads
300 ms
Wide · m = 2004levels / uncached path reads
40 ms

Minimum levels at full capacity, using N ≤ mh−1. Count one read per visited page, with no cache. Real occupancy can add levels. The latency is a teaching assumption, not a device benchmark.

An m-way search tree stores at most m−1 ordered keys per node. A node containing k keys has k+1 child-pointer positions, partitioning the search space into k+1 ordered ranges; some pointers may be null. Here all keys are distinct. A match at an ordinary search-tree node ends the search there.

A 4-way search-tree node

Root keys [10,30,35] have four child-pointer slots. The children show actual keys, with their permitted ranges below them.

Numbered cells: keysP0, P1, … → child subtrees

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text
Why use wide nodes?

If each node occupies a disk page, a binary tree may require many page reads along a long path. Keeping many separators in one page reduces the number of levels.

Height and I/O

Balanced binary trees have O(log₂ N) height. A wide balanced tree has O(logm N) height when its branching factor is proportional to m. A cached root does not require a disk read.

Why the level count works: derivation and full-capacity table

Let h be the number of levels, counting the root as level 1. In a perfectly filled m-way tree, every internal node has m children and every node has m−1 keys:

nodes = 1 + m + … + mh−1 = (mh−1)/(m−1)
keys = (m−1) × nodes = mh−1
Levels hKeys: m=2Keys: m=200
377,999,999
531319,999,999,999
712712,799,999,999,999,999
Ordinary m-way trees are not automatically balancedThe maximum degree alone does not guarantee a small height. B-trees add minimum occupancy and equal-leaf-depth rules to preserve balance after updates.

14.2Indexing and multilevel indexing

You need Chapter Five. Do you open chapters one by one?

THE BOOK ANALOGY

Find Chapter Five

The book is closed.
Where will you look first?

?

Contents

  1. Chapter One1
  2. Chapter Two15
  3. Chapter Three45
  4. Chapter Four51
  5. Chapter Five72
  6. Chapter Six90

Try checking chapters, then use the contents entry. These six entries come from the lecture’s book illustration.

Data pagesThe chapters of the file
Index pagesKeys that tell you where to go
Index of the indexOne compact starting page
See the contents-page illustration
Contents-page illustration highlighting Chapter Five on page 72.
The highlighted contents entry is the starting point for the multilevel-index analogy.

For a data file sorted by a distinct search key, a sparse index can store one entry per data block: the minimum key in that block and a pointer to it. Search chooses the entry with the largest key not exceeding the requested key. If the index spans several pages, build another sparse index over those pages.

Follow an index entry to its page

Example: 30 sorted records; five records per data block; at most three entries per index block. Search for record 23.

Index cell: minimum key / page pointer→ pointed-to page

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text

The root R has two entries, one for each first-level index page. I1 and I2 each have three entries, one for each data block they cover. These are minimum-key/pointer pairs, so an index page with k entries has k pointers; it is not drawn using the k+1 separator-pointer layout of a B-tree node.

Track

A concentric recording path on a magnetic disk surface.

Sector

An addressable segment of a disk track. SSDs do not have physical tracks.

Page and cluster

A database page is an I/O unit; a file-system cluster is an allocation unit containing one or more sectors. They need not have the same size.

Dynamic indexingA static index requires maintenance as data pages change. B-trees and B+ trees organize pages dynamically, splitting or combining them while preserving sorted routing and balance.

14.3Index-capacity exercises

Two small divisions decide how many pages an index needs.

Try the lecture questions first. Open the worked solutions when you are ready to check your reasoning.

Storage assumptions for these exercisesRecords and entries are fixed-size and unspanned: an entry never crosses a block boundary. Ignore page headers, slot directories, and compression. All page reads below assume an empty cache. Round capacities down and required page counts up.

Sparse-index example

30,000 sorted records; record size 100 B; block size 1024 B; key size 9 B; block pointer 6 B.

How many first-level sparse-index blocks are needed?

Choose an answer to see the reasoning.

Reveal the worked solution and page-read comparison
records per data block = ⌊1024/100⌋ = 10
data blocks = ⌈30,000/10⌉ = 3,000
index entry size = 9 + 6 = 15 B
index entries per block = ⌊1024/15⌋ = 68
first-level index blocks = ⌈3,000/68⌉ = 45
root index blocks = ⌈45/68⌉ = 1
Access methodWorst-case page readsAssumption
Sequential scan of data3,000No useful ordering or index
Binary search on data blocks12Sorted, directly addressable blocks
Binary search on 45 index blocks, then data6 + 1 = 7One index level; the selected block is scanned in memory
Two-level sparse index, then data1 + 1 + 1 = 3Root → first-level page → data page

For ordinary binary search over N candidate pages, ⌊log₂ N⌋+1 is a worst-case probe bound for N ≥ 1. These are not average search costs. An average requires a stated query distribution and search algorithm.

Dense multilevel-index example

16,384 records; record size 32 B; block size 1024 B; key size 6 B. Assume both record locators and upper-level block pointers occupy 10 B.

Which pair gives the first- and second-level index-block counts?

Choose an answer to see the reasoning.

Reveal all three index levels

Block capacity

Records per data block
1024 ÷ 3232 records
Data blocks
16,384 ÷ 32512 blocks
Dense index entry size
6 + 1016 B
Index entries per block
1024 ÷ 1664 entries

Build the index

  1. First level

    One entry per record

    ⌈16,384 ÷ 64⌉
    256blocks
  2. Second level

    One entry per first-level block

    ⌈256 ÷ 64⌉
    4blocks
  3. Third level

    One entry per second-level block

    ⌈4 ÷ 64⌉
    1root block

A complete uncached lookup traverses three index pages, then the data page: four page reads. The dense first level has one entry per record; the upper levels are sparse indexes over index pages.

14.4B-tree structure and order

Order 5 allows five children. How many keys fit?

4maximum keys
2minimum keys in a non-root node
1 depthfor every leaf
TEST THE OCCUPANCY RULE

When does this order-5 leaf need repair?

Read the complete B-tree rules and root exceptions
Convention used throughout this chapterFor B-trees take m ≥ 3. Order m means the maximum number of child pointers in an internal node. A B-tree node stores at most m−1 keys. This is different from the minimum-degree t convention, whose maximum is 2t children. Examples use distinct keys and external record pointers.
  • Every internal node with k keys has exactly k+1 non-null child pointers. The keys separate strictly ordered child ranges.
  • Every non-root node stores ⌈m/2⌉−1 through m−1 keys. Thus non-root internal nodes have ⌈m/2⌉ through m children.
  • An internal root has at least two children and one key. A leaf root may store 0 through m−1 keys; zero keys represents an empty tree.
  • All leaves are at the same depth. Leaves have no child subtrees.
  • In the indexed representation used here, every key has a record pointer, including keys stored in internal nodes.
Internal node with k keys:
P₀, ⟨K₁,RP₁⟩, P₁, …, ⟨Kk,RPk⟩, Pk
Keys in Pᵢ lie strictly between the adjacent separators.
Order-5 nodeChildrenKeys
Internal root2…51…4
Non-root internal node3…52…4
Non-root leaf02…4
Leaf root00…4

Order from a block-size constraint

Key = 9 B; record pointer = 7 B; child block pointer = 6 B; block = 512 B. An internal node with capacity p child pointers has p−1 key/record-pointer entries.

6p + (p−1)(9+7) ≤ 512
22p ≤ 528 ⇒ p ≤ 24

The maximum order is 24: p=24 occupies exactly 512 B; p=25 would occupy 534 B. Real page overhead can lower this capacity.

Maximum records in four full levels

For order 23, every full node stores 22 keys; each full internal node has 23 children. Counting the root as level 1:

22(1 + 23 + 23² + 23³) = 23⁴−1 = 279,840 entries

This counts each B-tree key/record-pointer entry once, including entries in internal nodes.

14.5B-tree insertion

Insert 55. Which key gets promoted?

The lecture’s leaf [50,56,57,58] has no spare slot. Inserting 55 produces [50,55,56,57,58]. Make your prediction, then step through the split.

Choose the entry that moves up from the overflowing leaf.

Choose an answer to see the reasoning.

Compare with the original insert-55 diagram
Insertion example: root [20,30], its right child [35,48,60,68], and the target leaf [50,56,57,58].
The illustration shows a branch of a larger tree: letters a, b, w, x, y, and z stand for omitted subtrees. The complete mini-example below uses that overflowing [35,48,60,68] node as its root so every child is visible. In the larger tree, promoting 56 gives root [20,30,56] without adding a level.

Search for the key first. If it is absent, insert its entry into the appropriate leaf in sorted order. An overflowing node has too many keys. Split it around a median, move the median entry to the parent, and reconnect all child pointers. Repeat upward if necessary. Splitting the root creates a new root and adds one level.

Insert 55 into an order-5 B-tree

Maximum four keys per node. Every child and record-pointer cell is shown; red marks temporary overflow.

Key / r(key): key and record pointerP0, P1, … → child pages

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text
Connect the animation to insertion pseudocode
insert(tree, entry):
    leaf = search_for_absent_key(tree, entry.key)
    insert_sorted(leaf.entries, entry)
    node = leaf
    while node has more than m - 1 entries:
        parent = node.parent
        left, median_entry, right = split(node)
        if parent is null:
            tree.root = new_root(median_entry, left, right)
            return
        replace node in parent by left, median_entry, right
        node = parent

The split transfers child pointers along with their corresponding key ranges. The promoted entry is removed from its old node; it is not duplicated in a B-tree leaf.

Order-4 construction exercise

Insert 2, 5, 10, 1, 6, 9, 4, 3, 12, 18, 20, 25. Here use top-down insertion: split any full three-key node before descending into it. This produces the following final tree. A bottom-up split convention can produce a different valid tree.

Final order-4 construction

Root [5]; internal children [2] and [9,12]; all twelve inserted keys appear exactly once.

Key / r(key): key and record pointerP0, P1, … → child pages

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text

14.6B-tree deletion

A leaf loses a key. Can its sibling lend one?

The two deletion examples start from the same tree. Delete 10 to see a rotation through the parent. Delete 3 to see why a merge is sometimes necessary.

Leaf [8] underflows. Its right sibling has [20,28,29]. What repairs it?

Choose an answer to see the reasoning.

For a leaf key, remove the entry directly. For an internal key, replace its entry with its predecessor (largest key in the left subtree) or successor (smallest key in the right subtree), then remove that replacement at its leaf. The examples below use bottom-up repair after deletion.

Delete 10: repair by borrowing

Order 5 requires at least two keys in every non-root node. Borrowing rotates entries through the parent separator.

Key / r(key): key and record pointerP0, P1, … → child pages

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text

Delete 3: repair by merging

An independent example starting from the original tree. The adjacent sibling cannot lend.

Key / r(key): key and record pointerP0, P1, … → child pages

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text
Borrow

An adjacent sibling with more than the minimum can lend. A parent separator moves down; a sibling entry moves up. For internal nodes, transfer the matching child pointer as well.

Merge

If no adjacent sibling can lend, combine the deficient node, a parent separator, and an adjacent sibling. Remove that separator and one child pointer from the parent.

Repair upward

If the parent underflows, repeat the repair above it. If an internal root becomes empty, replace it with its only child, reducing the height by one.

With this repair-after-deletion method, merging a one-key-deficient node and a minimum-size sibling fits within the node capacity. For order 5: 1 + 1 + 2 = 4 keys. No overflow split is needed during the repair.

14.7B+ tree structure

You found 50. How do you read the next records?

INTERNAL PAGES

Route the search

Separator keys tell you which child to follow. Their record pointers are gone, leaving room for more children.

LEAF PAGES

Read in order

Find the first record, then use the next-leaf link to continue the range scan.

Routing above, data entries at the leavesInternal nodes contain separator keys and child pointers only. Every indexed record has its data entry at a leaf. In this chapter a leaf entry is a key and an external record locator; implementations may instead store the record payload. Leaves are linked in sorted order.

Use internal order m and a separate leaf capacity q. Non-root internal nodes have ⌈m/2⌉…m children; with the half-full convention, non-root leaves have ⌈q/2⌉…q entries. An internal root has 2…m children. A leaf root has 0…q entries. All leaves have the same depth.

Internal: P₀, K₁, P₁, …, Kk, Pk
Leaf: ⟨K₁,RP₁⟩, …, ⟨Kq′,RPq′⟩, next
q′ is the current number of entries, at most q.

B+ point search and linked-leaf scan

This example has internal order m=3 and leaf capacity q=3. Each separator is the minimum key in its right subtree.

Leaf: key / r(key)P0, P1, … → childrennext ⇢ next leaf; ∅ = null

Every arrow connects its pointer slot to the referenced page. Enlarge for full-size labels.

Read this diagram as text
  • With this separator convention, equality follows the pointer to the right of the matching separator. For [30,60], P0 covers k<30, P1 covers 30≤k<60, and P2 covers k≥60.
  • Record pointers r5, r10, … appear only in leaves. Internal separator copies do not represent extra data records.
  • After finding the first qualifying leaf, a range scan follows next-leaf pointers in order. The final next pointer is null.
Searching for 30 matches an internal separator. Where is its record entry?

Choose an answer to see the reasoning.

B+ insertion and deletion

Insert at a leaf. If a leaf splits, keep all data entries in the two leaves, copy the minimum key of the new right leaf into the parent, and repair the next-leaf links. If an internal node splits, move its separating key up and redistribute child pointers. Splitting can propagate to the root.

Delete at the leaf. Borrow or merge if its occupancy falls below the chosen minimum, update affected separator keys to preserve the routing convention, and repair leaf links after a merge. Repair deficient ancestors as needed; an empty internal root is replaced by its only child.

14.8B+ tree capacity calculations

Same 512-byte page. Why do B+ internal nodes fit more children?

B-tree internal · order 24512 / 512 B
child pointers + keys + record pointers
B+ internal · order 34501 / 512 B
child pointers + keys

Dropping record pointers from internal nodes makes room for ten more child pointers in this exercise. Page headers are excluded, as in the slides.

Key = 9 B; record locator = 7 B; block pointer = 6 B; block size = 512 B. Ignore page overhead and reserve one next-leaf pointer per leaf.

Internal capacity
6p + 9(p−1) ≤ 512
15p ≤ 521
pmax = ⌊521/15⌋ = 34

34 child pointers and 33 separators; 501 B used. A 35-child node would require 516 B.

Leaf capacity
q(9+7) + 6 ≤ 512
16q ≤ 506
qmax = ⌊506/16⌋ = 31

31 key/record-pointer entries and one next pointer; 502 B used. A 32-entry leaf would require 518 B.

Here leaf capacity q counts data entries, and internal order p counts child pointers. Keeping these quantities separate avoids the ambiguous term “leaf order.”

CHANGE THE FILL LEVEL

Count records in four levels

24children per internal node³ ×22entries per leaf=304,128leaf data entries

The root follows the same occupancy assumption. Internal separator copies are excluded.

Why “70% full” needs a rounding convention

Four levels and 70% occupancy

Let the root be at level 0 and the leaves at level 3. Capacities are 34 children per internal node and 31 entries per leaf. Exactly 70% at every node is impossible because 0.7×34=23.8 and 0.7×31=21.7 are not integers. State the rounding rule before computing.

InterpretationChildren per internal nodeEntries per leafLeaf data entries
At least 70% full; uniform minimum integer occupancy⌈23.8⌉ = 24⌈21.7⌉ = 2224³ × 22 = 304,128
Textbook estimate using floors at every node⌊23.8⌋ = 23⌊21.7⌋ = 2123³ × 21 = 255,507

Both rows assume the same occupancy for every internal node, including the root. The floor estimate is actually about 67.6% of internal child capacity and 67.7% of leaf capacity. If 70% describes only an average, the exact record count is not determined without more information. Separator copies are not counted as data entries.

14.9B-tree versus B+ tree

What does the “+” change for a range query?

Which statement is correct?

Choose an answer to see the reasoning.

AspectB-treeB+ tree
Record entries in this index modelInternal nodes and leavesLeaves only
Equality searchMay finish in an internal nodeReaches the data entry at a leaf
Ordered range traversalIn-order traversal can visit internal nodes and leavesInitial search, then follow the leaf chain
Internal capacity for equal page/field sizesRecord pointers consume internal spaceMore space available for separators and child pointers
BalanceAll leaves at the same depthAll leaves at the same depth

Both are balanced multiway trees designed to reduce page accesses. B+ trees are particularly useful for ordered scans because the data entries occupy a linked sequence of leaves.

Applications and implementation choices

Database and file-system indexes use B-tree-family structures in several forms. MySQL documents InnoDB’s ordinary clustered and secondary indexes as B-trees. Clustered-index leaves contain row data; secondary-index leaves contain indexed keys and primary-key locators. Spatial indexes use R-trees. Do not infer the exact variant from a product category alone.

LevelDB and RocksDB use log-structured merge-tree designs. They should not be listed as examples of B+ tree storage engines.

Lecture source and further reading

References and source slides

The linked PowerPoint is the original lecture source. Use the corrected definitions, diagrams, and calculations on this page when they differ from those slides.