Hello! Welcome to the second module of our course, where we dive into the data structures that make databases fast: indexing.
Introduction
In our last module, we explored how a database manages data on disk and in memory. We saw how critical the buffer pool is for minimizing slow disk I/O. However, even with a perfectly tuned buffer pool, if the database has to scan an entire multi-gigabyte table to find a single record, performance will be terrible. The question we ended with was: how can we find data without doing a full scan?
The answer is an index. Today, we begin our study of the most important indexing structure in the database world: the B+ Tree. Our learning outcome is to explain why B+ trees are preferred over binary search trees for disk-based indexing. We will dissect the performance characteristics of storage hardware, see why a classic data structure like a binary search tree is a poor fit, and understand how the B+ Tree is specifically designed to solve these problems.
1. The Core Problem: The High Cost of Disk I/O
Before we can compare data structures, we must first deeply understand the environment they operate in. For a disk-based database, the single greatest performance bottleneck is accessing data from storage. The time difference between accessing data in RAM versus on an SSD or HDD is staggering.
To get a concrete feel for this, let's watch a video that breaks down the mechanics and costs of disk operations.
Simplest, Most Detailed Explanation of BTrees | Why do Databases use BTrees not BSTs or Arrays?
This video by Keerti Purswani provides an excellent, calculation-driven explanation of why disk I/O is so expensive. It establishes the foundational problem that indexing structures are built to solve.
Watch the segment from 01:11 to 08:53. Focus on these key points: The speed comparison between RAM (nanoseconds) and Hard Disk (milliseconds). How data is organized on disk into blocks (or pages). The critical fact that the database must read/write an entire block at a time. Follow the calculation showing why a sequential scan of 1 million records could take 100 seconds.
As the video clearly demonstrates, every disk I/O operation is costly. The primary goal of a disk-based index is therefore to minimize the number of disk blocks we need to read to find our data.
2. Why Binary Search Trees (BSTs) Are a Bad Fit for Disk
Given your background in data structures, you know that a balanced binary search tree offers excellent O(log n) performance for search, insert, and delete operations. So, why don't we use them for database indexes?
The answer lies in the O(log n) complexity itself when applied to disk. The height of a balanced BST is approximately log₂(n). For 1 million records, this is about 20 (2²⁰ ≈ 1 million). If the tree is stored on disk, each level we traverse to find a record could require a separate disk read, as each node might reside in a different disk block. A single lookup could therefore trigger up to 20 disk I/Os.
This article provides a concise summary of this problem.
Why Databases Don't Use Plain B-Trees for Indexes
Let's read a short section from a technical blog post that directly addresses the limitations of BSTs for databases.
Read the sections 'Binary Search Tree' and 'Why Can’t we use Binary Search Tree for Database Indexes?'. The key takeaway is the direct relationship between tree height and disk I/O.
The fundamental issue is that BSTs are tall and skinny. They are designed for in-memory operations where pointer chasing is cheap. For disk, where each "pointer chase" to a new block is incredibly expensive, this design is disastrous.
3. The B-Tree Solution: Short and Wide Trees
If a tall tree is bad for disk I/O, the logical solution is to create a tree that is as short as possible. This is the core idea behind the B-Tree.
Instead of nodes with only two children, a B-Tree node can have hundreds or even thousands of children. This is called an m-way search tree. By making the nodes "wider," we dramatically reduce the height of the tree.
How wide? The key design insight is to make the size of a single tree node equal to the size of a disk page (e.g., 4KB, 8KB, or 16KB). When the database performs one disk read to fetch a node, it gets a large block containing many keys to evaluate.
The following video provides a brilliant comparison, continuing the 1-million-record example.
Simplest, Most Detailed Explanation of BTrees | Why do Databases use BTrees not BSTs or Arrays?
Let's return to Keerti Purswani's explanation. This section compares the I/O cost of a BST directly against a B-Tree and shows the power of multi-level indexing.
Watch from 10:41 to 27:44. The video first builds the concept of multi-level indexing, which leads to the B-Tree structure. Then, pay close attention to the comparison table around 21:13. You will see a concrete calculation showing how a B-Tree can reduce the number of I/Os from ~20 (for a BST) to just 3 for the same 1 million records.
The result is a logarithmic complexity with a much larger base: O(logₘ n), where m is the "order" or fanout of the tree (the max number of children). Since m is large (e.g., >100), the height of the tree is extremely small. A B-Tree indexing billions of records might only be 4 or 5 levels deep. This means finding any record requires only 4-5 disk I/Os, a massive improvement over a BST.
Test your understanding!
Imagine you have a database with 1 billion (10⁹) records to index.
- For a balanced Binary Search Tree (BST), what is the approximate height of the tree and thus the worst-case number of disk I/Os for a lookup? (Hint:
2³⁰ ≈ 10⁹) - For a B-Tree with an order
m=1000, what is the approximate height of the tree and the worst-case number of I/Os? (Hint: The height is roughlylog₁₀₀₀(10⁹)).
Show answer
- BST: The height is
log₂(10⁹), which is approximately 30. This means a single lookup could cost up to 30 disk reads. - B-Tree: The height is
log₁₀₀₀(10⁹). Since1000 = 10³, we havelog₁₀³(10⁹). This evaluates to 3. A single lookup would cost at most 3 disk reads.
This clearly illustrates the power of a high-fanout tree for reducing I/O.
4. The "Plus" Advantage: Why B+ Trees are Even Better
Most modern databases use a specific variant called a B+ Tree. It refines the B-Tree design with two key modifications that provide significant performance benefits.
- Data Pointers Only in Leaf Nodes: In a standard B-Tree, keys and data pointers (or the data itself) can be stored in any node (internal or leaf). In a B+ Tree, the internal nodes store only keys, which act as "signposts" to guide the search. All actual data pointers are stored exclusively in the leaf nodes.
- Linked Leaf Nodes: All leaf nodes in a B+ Tree are linked together, forming a doubly-linked list.
This image provides an excellent visual comparison of the two structures.
So, what are the advantages of the B+ Tree design?
- Higher Fanout (Even Shorter Trees): Because internal nodes only store keys and not bulky data values/pointers, they are much smaller. This allows more keys to fit into a single node (a single disk page). A higher number of keys per node means a higher fanout (
m), which in turn leads to an even shorter tree and fewer I/Os for a lookup. - Efficient Range Queries: This is a huge advantage. If you need to execute a query like
SELECT * FROM employees WHERE age BETWEEN 30 AND 40, the process is simple. You traverse the tree once to find the first record (age 30), and then you just follow the linked list at the leaf level to scan all subsequent records in the range. In a standard B-Tree, you would have to traverse up and down the tree to find all the records in the range, which is much less efficient.
This brief video segment and article section summarize these advantages perfectly.
F2023 #08 - B+Tree Indexes (CMU Intro to Database Systems)
Let's hear a quick summary from the CMU Database course on the difference between B-Trees and B+ Trees.
Watch the clip from 20:16 to 22:36. It directly contrasts the two structures, highlighting the benefits of storing values only in the leaves for sequential access and better concurrency.
Why Databases Don't Use Plain B-Trees for Indexes
Finally, this section from the blog post we viewed earlier lists the advantages of the B+ tree structure in a clear, easy-to-digest format.
Read just the subsection titled 'Advantages of B+ Tree'. It reinforces the points about fitting more data in internal nodes and enabling efficient scans.
Conclusion
Today we established the fundamental principles behind disk-based indexing. We saw how the physical constraints of storage hardware dictate the design of efficient data structures.
Key Takeaways:
- The primary goal of a disk-based index is to minimize disk I/O operations, which are orders of magnitude slower than memory access.
- Binary Search Trees (BSTs) are a poor choice for disk because their tall, skinny structure leads to a high number of I/Os for a single lookup (tree height ≈ I/Os).
- B-Trees solve this by being short and wide. Their high fanout (many children per node) dramatically reduces tree height, corresponding to
O(logₘ n)I/Os. - B+ Trees are the preferred variant in modern databases because:
- They store data pointers only in leaf nodes, allowing internal nodes to hold more keys, which increases fanout and further reduces tree height.
- Their linked leaf nodes make range queries and full index scans extremely efficient.
Preview of the Next Lesson:
Now that we understand why B+ Trees are the right choice, our next step is to understand how they work dynamically. In the next lesson, we will get practical and learn how to implement insertion and deletion operations in a B+ tree, including handling the critical logic of node splits and merges.