B+Tree Indexing

From “index makes query faster” to “I can implement and debug one.”

1 / 32

The core pain

A table scan asks too much:

look at page
look at next page
look at next page
...

An index should reduce the number of pages touched.

2 / 32

Wrong first mental model

A database B+Tree is not mainly a binary tree.

It is a page-aware tree.

One node means one page-sized chunk of sorted keys.

3 / 32

B+Tree shape

internal pages: separators + child pointers
leaf pages:     actual key/value entries
leaf links:     ordered sideways scan
4 / 32

Why it stays shallow

High fanout.

fanout 200
height 2 -> ~200 leaves
height 3 -> ~40,000 leaves
height 4 -> ~8,000,000 leaves
5 / 32

Module ladder

  1. Page math
  2. Search
  3. Range scan
  4. Insert with splits
  5. Invariant validation
  6. Bulk loading
6 / 32

Internal node routing

For separators:

[10 | 20 | 40]

Children represent:

<10
10..19
20..39
>=40
7 / 32

Equality goes right

Search key 20 routes to the child right of separator 20.

The separator is the lower bound of the right subtree.

8 / 32

Routing rule

choose first separator greater than key
otherwise choose rightmost child

This is upper_bound.

9 / 32

Leaf lookup rule

Inside a leaf:

find first key >= target
if equal -> found
else -> missing

This is lower_bound.

10 / 32

Search walkthrough

          [10 | 20]
        /     |     \
 [1,4,7] [10,13] [20,25,30]

Search 13: root -> middle leaf -> found.

Search 20: root -> right leaf -> found.

11 / 32

Range scan

Query:

lo <= key <= hi

Algorithm:

  1. Descend using lo.
  2. Scan current leaf.
  3. Follow Next.
  4. Stop after hi.
12 / 32

Without links:

find next key by going back through tree

With links:

move to next leaf page
13 / 32

Insert overview

  1. Descend to leaf.
  2. Insert or replace key/value.
  3. If overflow, split.
  4. Promote separator to parent.
  5. Repeat upward if needed.
14 / 32

Leaf split

Order = 3

[1,2,3,4] overflow

left:  [1,2]
right: [3,4]
promote: 3

Promoted key stays in the right leaf.

15 / 32

Internal split

[10,20,30,40] overflow

left:    [10,20]
promote: 30
right:   [40]

Promoted key moves up and is removed from the child.

16 / 32

Split return pattern

split bool
promote int
right *Node

The child reports what happened.

The parent decides where to insert the separator and right child.

17 / 32

Root split

When the root splits, height increases.

new root: [promoted]
          /        \
       left        right
18 / 32

Common bug 1

Routing equality left.

Symptom: keys equal to separators disappear.

Fix: internal routing uses first separator greater than key.

19 / 32

Common bug 2

Leaf split promotes the wrong key.

Correct: first key of the right leaf.

20 / 32

Common bug 3

Internal split keeps the promoted key in a child.

Correct: internal promoted key moves up.

21 / 32

Common bug 4

Parent inserts right child in the wrong position.

Correct: if child idx split, new right child goes at idx+1.

22 / 32

Validator mindset

A few successful lookups do not prove the tree is valid.

Check invariants.

23 / 32

Validator checklist

  • sorted keys
  • correct child count
  • separator correctness
  • max keys per node
  • leaves at same depth
  • valid leaf links
24 / 32

Bulk load

Sorted input lets us build bottom-up:

fill leaves -> link leaves -> build parents -> repeat
25 / 32

Bulk load example

pairs: 1 2 3 4 5 6 7 8
leaves: [1,2,3] -> [4,5,6] -> [7,8]
root: [4,7]
26 / 32

Real database mapping

Toy model:

int key -> int value

Real model:

composite key -> tuple pointer / primary key / included columns
27 / 32

Composite index intuition

Index on:

(tenant_id, created_at, id)

Sorted by tenant first.

This explains the left-prefix rule.

28 / 32

Covering index intuition

If the leaf has all needed columns, the engine may avoid table lookup.

29 / 32

B+Tree is good for

  • equality lookup
  • range lookup
  • ordered scan
  • min/max
  • matching ORDER BY
30 / 32

B+Tree is not magic

It can be weak for:

  • low-selectivity predicates
  • wrong index prefix
  • heavy random write pressure
  • workloads better served by hash or LSM structures
31 / 32

Final standard

After this module, learners should be able to:

  • implement the core algorithms,
  • explain every separator movement,
  • debug structural corruption,
  • connect index shape to query performance.
32 / 32
Use arrow keys or click edges to navigate. Press H to toggle help, F for fullscreen.