For over four decades, the B+ Tree has been the foundational data structure powering relational database storage engines, including PostgreSQL, MySQL (InnoDB), Oracle, Microsoft SQL Server, and SQLite.
To engineer high-performance systems, you must understand how B+ Trees organize physical disk pages, execute binary searches inside memory buffers, manage node splits, and handle the steep penalty of Write Amplification.
1. Why B+ Trees Dominate: Branching Factor & Low Tree Height
Unlike in-memory binary search trees (AVL, Red-Black Trees) where each node has a branching factor of 2 (), database B+ Trees are optimized for disk block size ().
The Branching Factor Equation:
With a page size of (MySQL InnoDB default) and an average index key + pointer size of :
Key Takeaway: A 3-level B+ Tree can index 125 million rows with only 3 disk reads, and because the root and internal levels remain permanently cached in RAM, most single-row point lookups require exactly 1 physical disk read!
2. Anatomy of a Database Page: The Slotted-Page Architecture
In page-based engines, files on disk are divided into fixed-size chunks (e.g. in PostgreSQL, in InnoDB).
To support variable-length columns (such as VARCHAR and JSONB) without fragmentation, pages use a Slotted-Page Layout:
Why Slotted Pages?
- An index pointer never points to a raw byte offset on disk; it points to a Tuple ID (TID) = (Page Number, Slot Index).
- If a row is updated and changes size, the database can move the tuple anywhere inside the page and update the slot pointer, without invalidating secondary indexes across the entire database!
3. Node Splitting and Page Merging Mechanics
When an INSERT arrives at a leaf page that has insufficient free space, the engine must perform a Page Split:
The 50/50 Split vs Right-Leaning Split:
- Random Inserts: Pages split 50/50, resulting in an average page fill factor of (33% wasted space due to fragmentation).
- Auto-Increment Monotonic Inserts: InnoDB detects sequential inserts and performs a 90/10 or 100/0 Split, keeping pages 100% full and avoiding wasted space.
4. Concurrency Control: Latch Crabbing (Coupling)
How do multiple threads traverse and mutate a B+ Tree simultaneously without corrupting node pointers?
Storage engines use Latch Crabbing (Latch Coupling):
5. The Fatal Flaw of B-Trees: High Write Amplification
While B+ Trees deliver stellar point reads and range scans, they suffer from severe Write Amplification:
The Math of B-Tree Write Amplification:
Suppose you update a single 20-byte user_status string in a row:
- Engine writes the WAL delta record: .
- Engine writes the modified page to MySQL's Doublewrite Buffer: .
- Engine flushes the dirty table page to physical disk: .
- If a secondary index page is updated, repeat steps 2 & 3: .
On write-heavy workloads (such as IoT telemetry, high-frequency logs, and real-time streaming), B+ Trees saturate SSD write channels and trigger flash drive wear-out.
6. Code Deep-Dive: In-Memory B+ Tree Node Search & Split Engine
7. Production Failure Postmortem: Table Bloat & Latch Contention
Incident Overview:
In 2020, an e-commerce marketplace experienced 10-second checkout query timeouts during Black Friday, caused by severe B-Tree page bloat and root-node latch contention in PostgreSQL.
What Happened:
- High-frequency inventory decrement queries repeatedly updated stock rows:
UPDATE items SET stock = stock - 1. - PostgreSQL's MVCC architecture writes a new tuple version for every update and marks the old version as dead.
- The autovacuum worker could not keep up with the update volume, causing leaf pages to bloat with 85% dead tuples.
- B+ Tree height grew from 3 levels to 5 levels, expanding the index size from to (exceeding server DRAM buffer pool).
- All concurrent checkout workers competed for read/write latches on internal index pages, causing CPU thread starvation.
Remediation:
- Scheduled off-peak
pg_repackto rebuild bloated B+ Trees online with zero table locking. - Tuned PostgreSQL autovacuum settings (
autovacuum_vacuum_scale_factor = 0.02) to aggressively reclaim dead slots before page splits occur.