DEV Community

Cover image for How Databases Store Data: B+ Tree Explained Simply for Beginners (With Real-World Examples)
Vivek Upadhyay
Vivek Upadhyay

Posted on

How Databases Store Data: B+ Tree Explained Simply for Beginners (With Real-World Examples)

Description: Learn how B+ Trees work in databases like MySQL, PostgreSQL, and MongoDB. This beginner-friendly guide explains database indexing, disk I/O, leaf nodes, range queries, and why B+ Trees are the industry standard — with relatable real-world examples.


🎯 What Will You Learn From This Blog?

  • Understand why databases can't simply store data in a plain file — and what breaks when they try.
  • Learn what a B+ Tree is, how it works step by step, and why it powers almost every database you'll ever touch — MySQL, PostgreSQL, MongoDB, SQLite, and more.
  • Master core database concepts like disk I/O, leaf nodes, non-leaf nodes, range queries, and logarithmic search — explained so simply you could teach them to your non-tech friend over chai.

🔤 SECTION 1 — Jargon Buster (Glossary for Beginners)

Before we jump into how databases store data, let's kill every confusing term upfront. Read this section like a mini-dictionary.


Term: Database
Simple Definition: A digital cupboard where your app stores and finds information.
Real-World Example: Think of your phone's contact list. All names, numbers, and photos are stored in one organized place. That organized place is a database.


Term: SQL (Structured Query Language)
Simple Definition: A language you use to talk to a database — ask questions, add data, or delete data.
Real-World Example: When you type a name in your phone's contact search bar, you're basically running a query. SQL is how developers write that search instruction for a database.


Term: NoSQL
Simple Definition: A different style of database that doesn't require fixed rows and columns like a spreadsheet.
Real-World Example: SQL is like a school attendance register — fixed columns: Roll No, Name, Present/Absent. NoSQL is like a personal diary — each page can look different. One page has a list, another has a paragraph, another has a drawing.


Term: MongoDB
Simple Definition: A popular NoSQL database that stores data in flexible documents (like JSON files).
Real-World Example: Imagine each student in a school has a flexible profile folder. One student's folder has 5 pages, another has 8. Some have photos, some don't. MongoDB lets data be flexible like that.


Term: Storage Engine (e.g., WiredTiger)
Simple Definition: The behind-the-scenes system inside a database that decides HOW data is physically saved on your hard disk and HOW it's found.
Real-World Example: Think of a grocery store manager. Customers don't care how products are arranged in the warehouse. The manager (storage engine) decides which shelf gets which item and knows the fastest way to find anything.


Term: B+ Tree
Simple Definition: A smart tree-shaped structure that databases use to organize data so finding anything takes just a few steps, even among billions of records.
Real-World Example: Think of the table of contents in a textbook. Instead of flipping every page to find "Chapter 7: Photosynthesis," you go to the table of contents → Unit 3 → Chapter 7 → Page 142. A B+ Tree works like a multi-level table of contents.


Term: O(n) Complexity (Big O Notation)
Simple Definition: A way to describe speed. O(n) means "if data doubles, the work doubles too." It's slow for big data.
Real-World Example: Imagine you lost your keys somewhere in your house. You check every room, every drawer, every pocket one by one. If your house is twice as big, it takes twice as long. That's O(n).


Term: Logarithmic Complexity — O(log n)
Simple Definition: Even if data grows massively, the work barely increases. Super fast.
Real-World Example: You're playing the "guess my number between 1 and 100" game. You say 50, friend says "higher." You say 75, "lower." You say 62, "higher." Each guess cuts possibilities in HALF. Even for 1 to 1 billion, you only need ~30 guesses. That's O(log n).


Term: Disk I/O (Input/Output)
Simple Definition: Reading data from or writing data to a hard drive. It's one of the SLOWEST things a computer does.
Real-World Example: Your RAM is like the kitchen counter — everything you need is right there, instantly. Your hard drive is like the storage room in the basement. Every time you need an ingredient from the basement, you walk down, grab it, walk back up. Each trip = one disk I/O. Trips are slow. You want fewer trips.


Term: 4 KB Disk Block (Page)
Simple Definition: The smallest chunk of data a hard drive reads at once — usually 4,096 bytes.
Real-World Example: Imagine a vending machine that only drops items in packs of 10. Even if you need just 1 candy, you get a pack of 10. Similarly, even if you need 1 byte of data, the disk gives you a whole 4 KB block.


Term: Leaf Node
Simple Definition: The bottom-level boxes in a B+ Tree where the actual data (real database rows) lives.
Real-World Example: In a mall directory, the leaf node is the actual shop where you buy things. The signs just pointed you there.


Term: Non-Leaf Node (Internal Node)
Simple Definition: The upper-level boxes in a B+ Tree that give directions but DON'T hold any real data.
Real-World Example: The floor directory in a mall: "Clothes → Floor 2, Electronics → Floor 3." These signs don't sell anything. They just point you the right way.


Term: Indexing
Simple Definition: Creating a shortcut map so the database doesn't scan every row to find what you need.
Real-World Example: The index at the back of a textbook. Instead of reading 500 pages to find "Newton's Laws," you check the index: "Newton's Laws — Page 87." Jump there directly.


Term: Linear Scan
Simple Definition: Checking every single record from start to finish. Slow and painful with big data.
Real-World Example: Looking for your friend in a crowd of 10,000 people by walking up to each person and asking "Are you Rahul?" One. By. One.


Term: Range Query
Simple Definition: Asking the database for all records between two values. Example: "All orders from January to March."
Real-World Example: Telling a shopkeeper: "Show me all T-shirts between ₹500 and ₹1000." The shopkeeper finds the ₹500 section, then grabs everything up to ₹1000.


Term: Point Lookup
Simple Definition: Asking the database for ONE specific record.
Real-World Example: Telling a shopkeeper: "Give me the blue Nike T-shirt, size M, product code NKE-2847." One exact item.


Term: Rebalancing
Simple Definition: When you add or remove data, the B+ Tree automatically reorganizes itself to stay evenly structured.
Real-World Example: Imagine a classroom where one row has 15 students and another has 3. The teacher redistributes students so every row has roughly equal students. That's rebalancing.


Now you speak the language. Let's dive in! 🚀


📖 SECTION 2 — Main Content: Understanding How Databases Store Data


Topic 1: Why Storing Data in a Simple File Fails (The Naive Approach)

Explanation

When you're new to coding, the first idea for storing data sounds perfectly logical: just write everything into a file, line by line. A CSV file, a text file, a JSON file — just append records sequentially.

For 10 records? Works great. For 10 million records? Complete disaster. Here's why:

  • Searching is painfully slow. There's no shortcut. You scan from line 1 until you find what you need.
  • Inserting in sorted order means rewriting the file. Adding a record in the middle forces you to shift everything after it.
  • Deleting leaves gaps that must be closed by rewriting.
  • Updating is risky. If the new data is bigger than the old data, it won't fit in the same space.

All these operations are O(n) — meaning if your data doubles, the time doubles too. That's a death sentence for performance at scale.

📱 Real-World Example: Your Phone's Contact List (Without Search)

Imagine your phone stored contacts in a simple notepad file — just a list:

Amit - 9876543210
Priya - 9123456789
Rahul - 9988776655
... (50,000 contacts)
Zara - 9111222333
Enter fullscreen mode Exit fullscreen mode

Now you want to call Rahul. Without a search feature, you'd scroll from Amit all the way down, checking each name, until you find Rahul. With 50,000 contacts, this could take minutes.

Now imagine adding a new contact "Mohit" in alphabetical order. You'd have to move every contact from "N" to "Z" one position down to make space. That's rewriting thousands of entries.

This is exactly the problem databases face when they store data in a simple file.

Technical Example

File: users.dat

Offset 0:      {id: 1, name: "Alice", city: "NYC"}
Offset 100:    {id: 2, name: "Bob", city: "LA"}
Offset 200:    {id: 3, name: "Charlie", city: "Chicago"}
...
Offset 9999900: {id: 100000, name: "Zara", city: "Miami"}
Enter fullscreen mode Exit fullscreen mode

Search for id = 50000:
No index exists. Database reads from offset 0, checks each record: id=1? No. id=2? No. id=3? No... all the way to id=50000. That's 50,000 disk reads in the worst case.

Insert id = 1.5 (between Alice and Bob):

  1. Find the insertion point.
  2. Shift every record after offset 100 forward by 100 bytes.
  3. Write the new record.
  4. Essentially rewrite 99,999 records. O(n).

Update name: "Bob"name: "Alexander":
"Bob" = 3 characters. "Alexander" = 9 characters. The new name doesn't fit in the same space. Every record after Bob must be shifted by 6 bytes. Again, O(n).

📊 Image

Why Does This Matter for Developers?

If you've ever built a small project that reads/writes to a JSON file, you've used this approach. It works fine for a to-do app with 50 tasks. But at a company — an e-commerce platform, a banking app, a food delivery service — you're dealing with millions of records. A linear scan that takes 30 seconds per query will make your app unusable. That's why every production database uses something smarter.


Topic 2: What Is a B+ Tree? (The Core Data Structure Behind Every Database)

Plain English Explanation

A B+ Tree is the data structure that solves all the problems we just discussed. It's a tree-shaped index that organizes your data into levels, so the database can jump straight to the right location in just 3-4 steps — even with billions of records.

Here's the key idea:

A B+ Tree is like a multi-level navigation system. At each level, you eliminate a MASSIVE chunk of irrelevant data. Within 3-4 levels, you've found your exact record.

The tree has three types of nodes:

  • Root node (the top — your starting point)
  • Internal nodes (the middle — signposts that guide you)
  • Leaf nodes (the bottom — where the actual data lives)

This structure gives O(log n) search performance — meaning even with 1 billion records, you find anything in 3-4 steps.

🛒 Real-World Example: Finding a Product in a Supermarket

You walk into a massive supermarket with 100,000 products. You need to find Maggi noodles.

Without a B+ Tree (naive approach): You start at Aisle 1, Shelf 1 and walk through every aisle, checking every product. "Rice? No. Bread? No. Shampoo? No." You'd check thousands of products before finding Maggi. This could take an hour.

With a B+ Tree (smart approach):

  • Level 1 — Store entrance sign (Root): "Groceries → Left side. Electronics → Right side. Clothing → Upstairs."
    • You go left. ✅
  • Level 2 — Groceries section sign (Internal node): "Snacks & Instant Food → Aisle 7. Dairy → Aisle 12. Beverages → Aisle 15."
    • You go to Aisle 7. ✅
  • Level 3 — Aisle 7 shelf label (Internal node): "Chips → Top shelf. Noodles → Middle shelf. Biscuits → Bottom shelf."
    • You look at the middle shelf. ✅
  • Level 4 — Middle shelf (Leaf node): There's Maggi! Right there, between Yippee and Top Ramen. 🎉

Four steps. That's it. In a store with 100,000 products. That's the power of a B+ Tree.

Technical Example

A simplified B+ Tree storing employee IDs:

                      [50]                    ← Root Node
                     /    \
              [20, 35]    [65, 80]           ← Internal Nodes
             /   |   \    /   |   \
     [10,15,20] [25,30,35] [40,45,50] [55,60,65] [70,75,80] [85,90,95]
                                                                  ↑
                                                           Leaf Nodes
                                                    (actual data lives here)
Enter fullscreen mode Exit fullscreen mode

Searching for Employee ID = 75:

  1. Root [50]: Is 75 > 50? Yes → go right.
  2. Internal [65, 80]: Is 75 ≥ 65 and < 80? Yes → go to middle child.
  3. Leaf [70, 75, 80]: Scan this small node → Found ID 75! ✅

Only 3 steps to find one record among potentially millions. Compare that to scanning every record one by one.

📊 Image

Why Does This Matter for Developers?

Every time you write this SQL:

CREATE INDEX idx_user_email ON users(email);
Enter fullscreen mode Exit fullscreen mode

The database builds a B+ Tree behind the scenes. The keys in the tree are email addresses, and the leaf nodes point to (or contain) the actual rows. When you later search:

SELECT * FROM users WHERE email = 'rahul@gmail.com';
Enter fullscreen mode Exit fullscreen mode

MySQL doesn't scan 10 million rows. It traverses the B+ Tree in 3-4 steps and returns Rahul's record in milliseconds. Now you know what's happening under the hood!


Topic 3: Why B+ Trees Use 4 KB Disk Blocks (Database Page Size Explained)

Plain English Explanation

Here's a fact most beginners don't learn until much later: your hard drive can't read just 1 byte of data. Every time you ask the disk for anything — even a single character — it reads a whole block of data, typically 4 KB (4,096 bytes).

This is because physically moving the disk read-head is expensive and slow. Since you're making the trip anyway, might as well bring back a full chunk of data.

B+ Trees are designed to exploit this. Each node in a B+ Tree is exactly the size of one disk block (4 KB or more). So every time the database reads one node, it uses exactly one disk I/O — no wasted reads, no partial reads.

This is why B+ Trees are so efficient with disk-based storage.

🍕 Real-World Example: Ordering Pizza for a Group

Imagine you're ordering pizza for a party. The pizza place charges a flat ₹50 delivery fee per trip, regardless of how many pizzas you order.

  • Bad approach: Order 1 pizza, pay ₹50 delivery. Need another? Order again, pay ₹50 again. 10 friends = 10 trips = ₹500 in delivery alone. 😩
  • Smart approach: Figure out how many pizzas fit in the delivery bag (let's say 5) and order 5 at once. 10 friends = 2 trips = ₹100 delivery. ✅

The delivery trip is like a disk I/O (slow and expensive). The delivery bag capacity is like the 4 KB disk block. B+ Trees stuff each node with as much useful data as possible so every "trip" (disk read) brings back maximum value.

Technical Example

Let's calculate how powerful this is:

  • Each key in our B+ Tree = 8 bytes (an integer like a user ID).
  • Each pointer to a child = 8 bytes.
  • One entry = key + pointer = 16 bytes.
  • One disk block = 4,096 bytes.
  • Entries per node = 4,096 ÷ 16 ≈ 256.

So each non-leaf node can have 256 children. Let's see how the tree scales:

Tree Level Nodes at This Level Total Records Reachable
Level 1 (Root) 1 256 paths
Level 2 256 65,536 paths
Level 3 65,536 16,777,216 paths
Level 4 (Leaves) 16,777,216 ~16.7 million records

Just 4 disk reads can search through 16.7 MILLION records.

And here's the bonus: the root node is almost always cached in RAM (because it's accessed so frequently). So it's really 3 disk reads for 16.7 million records.

With InnoDB (MySQL's default engine), the default page size is 16 KB, which means even higher branching factors and even fewer levels needed.

📊 Image

Why Does This Matter for Developers?

When you see MySQL settings like innodb_page_size = 16384 or PostgreSQL's block_size = 8192, now you understand what they mean. These settings control the node size of the B+ Tree. Larger page sizes = more keys per node = fewer levels = fewer disk reads = faster queries.

This also explains why adding too many indexes can slow down writes. Each index is a separate B+ Tree. Every insert into the table means updating multiple B+ Trees. More trees = more disk writes.


Topic 4: Leaf Nodes in B+ Trees — Where Your Actual Data Lives

Plain English Explanation

In a B+ Tree, there's a strict rule:

ALL actual data rows are stored ONLY in the leaf nodes — the very bottom level of the tree.

The nodes above (root, internal nodes) only contain keys and pointers — navigation information. They're like road signs. The actual destination is always at the bottom.

And here's the most important feature: leaf nodes are linked together like a chain. Each leaf node has a pointer to the next leaf node. This creates a sorted linked list at the bottom of the tree.

This chain is what makes range queries incredibly fast — but we'll get to that soon.

🏬 Real-World Example: A Shopping Mall

Think of a 3-floor shopping mall:

  • Floor 3 (Root): A big board at the entrance says "Food → Floor 1, Clothes → Floor 2, Electronics → Floor 3." This board doesn't sell anything. It just gives directions.
  • Floor 2 (Internal): Signs say "Men's Clothing → Left Wing, Women's Clothing → Right Wing." Again, no products here. Just directions.
  • Floor 1 (Leaf): This is where the actual shops are. You walk in, pick up a shirt, and buy it.

Now imagine all the shops on Floor 1 are connected by a corridor. You can walk from Shop 1 → Shop 2 → Shop 3 → Shop 4 without going back upstairs. That corridor is the linked list between leaf nodes.

Technical Example

Leaf 1              Leaf 2              Leaf 3              Leaf 4
┌──────────────┐   ┌──────────────┐   ┌──────────────┐   ┌──────────────┐
│ ID:1  Amit    │──→│ ID:4  Deepa  │──→│ ID:7  Gaurav │──→│ ID:10 Jaya   │
│ ID:2  Bhavna  │   │ ID:5  Esha   │   │ ID:8  Harsh  │   │ ID:11 Kiran  │
│ ID:3  Chirag  │   │ ID:6  Farhan │   │ ID:9  Isha   │   │ ID:12 Laksh  │
└──────────────┘   └──────────────┘   └──────────────┘   └──────────────┘
       ↑                  ↑                  ↑                   ↑
   Actual rows!      Actual rows!       Actual rows!        Actual rows!

   ──→ = "Next" pointer (linked list connecting all leaves)
Enter fullscreen mode Exit fullscreen mode

Key points:

  • Every leaf contains real data — names, IDs, everything.
  • Arrows (→) connect each leaf to the next — sorted, sequential.
  • Non-leaf nodes above only have keys like [4], [7], [10] — just enough to guide you down to the right leaf.

📊 Image

Why Does This Matter for Developers?

In MySQL InnoDB, the primary key index is a clustered index — meaning the leaf nodes of the primary key's B+ Tree contain the entire row of data. When you run:

SELECT * FROM users WHERE id = 42;
Enter fullscreen mode Exit fullscreen mode

The database traverses the B+ Tree, reaches the leaf node, and finds the complete row (id, name, email, everything) right there. No extra lookup needed.

This is also why choosing a good primary key matters. An auto-incrementing integer ID keeps insertions sequential (always at the end of the leaf chain), which avoids expensive rebalancing. A random UUID as a primary key causes random inserts throughout the tree, leading to more splits and slower writes.


Topic 5: Non-Leaf Nodes — The Signpost System That Guides Every Search

Plain English Explanation

Non-leaf nodes are the upper levels of the B+ Tree — the root and internal nodes. Their ONLY job is to point you in the right direction. They say, "The record you're looking for is somewhere in THAT subtree."

They contain:

  1. Keys — boundary values that divide the data range.
  2. Pointers — addresses pointing to child nodes.

They do NOT contain actual data rows. Think of them as the table of contents of a book — helpful for navigation, but you can't read the actual chapter content from the table of contents.

🗺️ Real-World Example: Google Maps Navigation

Imagine you're using Google Maps to drive from Delhi to a specific restaurant in Mumbai.

  • Level 1 (Root — Broad direction): "Head South on NH48 toward Maharashtra."
  • Level 2 (Internal — Getting closer): "Take the Mumbai exit. Enter Western Express Highway."
  • Level 3 (Internal — Almost there): "Turn left on Linking Road, Bandra."
  • Level 4 (Leaf — Destination): "You've arrived! The restaurant is on your right." 🎉

Each navigation instruction (turn-by-turn direction) is a non-leaf node. It doesn't have your food — it just tells you where to go. The restaurant (where you actually eat) is the leaf node.

Technical Example

Non-leaf node: [30 | 60]

            /         |         \
           ↓          ↓          ↓
       Child A     Child B     Child C
    (keys < 30)  (30 ≤ keys < 60)  (keys ≥ 60)
Enter fullscreen mode Exit fullscreen mode

Searching for key = 45:

  1. Compare 45 with 30 → 45 ≥ 30, so skip Child A.
  2. Compare 45 with 60 → 45 < 60, so go to Child B.
  3. Child B might be another non-leaf (continue navigating) or a leaf (data found!).

Here's the search logic in simple pseudocode:

def search_b_plus_tree(node, target_key):
    if node.is_leaf():
        # We're at the bottom! Scan this node for the key.
        for record in node.records:
            if record.key == target_key:
                return record  # Found it! 🎉
        return None  # Not here.

    # Non-leaf node: find which child to visit
    for i, key in enumerate(node.keys):
        if target_key < key:
            return search_b_plus_tree(node.children[i], target_key)

    # Target is bigger than all keys → go to the last child
    return search_b_plus_tree(node.children[-1], target_key)
Enter fullscreen mode Exit fullscreen mode

At each non-leaf node, you make one comparison and eliminate a massive portion of the tree. That's what gives B+ Trees their O(log n) speed.

📊 Image

Why Does This Matter for Developers?

When you run EXPLAIN on a SQL query and see the query plan:

EXPLAIN SELECT * FROM orders WHERE order_id = 1234;
Enter fullscreen mode Exit fullscreen mode

If the output shows type: ref or type: const (instead of type: ALL), it means MySQL is using the non-leaf nodes of a B+ Tree index to navigate directly to the right leaf node. type: ALL means it's doing a full table scan — ignoring the tree entirely. Understanding this helps you read query plans and debug slow queries at work.


Topic 6: How B+ Trees Speed Up Find Operations (Database Query Performance)

Plain English Explanation

Let's be very explicit about the performance difference between a naive file scan and a B+ Tree search.

  • Naive file: O(n) — check every record. 1 million records = up to 1 million reads.
  • B+ Tree: O(log n) — traverse 3-4 levels. 1 million records = 3-4 reads.

The "log" base here isn't 2 (like in a binary tree). It's typically 256 or higher (the branching factor of the tree). That means each step eliminates not half, but 99.6% of the remaining options.

📱 Real-World Example: Finding a Song on Your Phone

You have 10,000 songs on your phone.

Without search (linear scan): You scroll through your entire music library, song by song, reading each title: "Aadat? No. Believer? No. Closer? No..." until you find "Shape of You." Could take 10 minutes of scrolling.

With search (B+ Tree-like approach): You type "Shape" in the search bar. Instantly, the phone narrows down to songs starting with "Sha..." then "Shape..." and shows you "Shape of You" in under 1 second.

That's the difference between O(n) and O(log n). The search bar uses an index (similar to a B+ Tree) to skip straight to the answer.

Technical Example

Number of Records Linear Scan (O(n)) B+ Tree Search (O(log₂₅₆ n))
1,000 Up to 1,000 disk reads 1-2 disk reads
100,000 Up to 100,000 disk reads 2-3 disk reads
10,000,000 Up to 10,000,000 disk reads 3 disk reads
1,000,000,000 Up to 1,000,000,000 disk reads 3-4 disk reads

Look at the last row. 1 billion records.

  • Linear scan: potentially 1 billion disk reads. At 10ms per read, that's 115 days.
  • B+ Tree: 4 disk reads. At 10ms per read, that's 40 milliseconds.

115 days vs 40 milliseconds. That's not an improvement — it's a miracle.

📊 Image

Why Does This Matter for Developers?

This is why every experienced developer and DBA says: "Add an index on columns you filter by."

Without an index:

-- No index on "email" → full table scan → O(n) → SLOW 🐌
SELECT * FROM users WHERE email = 'rahul@gmail.com';
Enter fullscreen mode Exit fullscreen mode

With an index:

-- Create a B+ Tree index on "email"
CREATE INDEX idx_email ON users(email);

-- Now the same query uses the B+ Tree → O(log n) → FAST ⚡
SELECT * FROM users WHERE email = 'rahul@gmail.com';
Enter fullscreen mode Exit fullscreen mode

The query goes from 30 seconds to 2 milliseconds. Same query, same data, just a B+ Tree index doing its magic.


Topic 7: How B+ Trees Handle Insert, Update, and Delete Efficiently

Plain English Explanation

In a naive file, any modification (insert, update, delete) potentially means rewriting the entire file. That's O(n).

In a B+ Tree, modifications are targeted — you only touch the specific nodes involved:

  1. Insert: Navigate to the correct leaf node (O(log n)), add the record. If the leaf is full, it splits into two. The parent gets a new key. Occasionally, splits can ripple upward (called rebalancing), but this is rare.

  2. Delete: Navigate to the leaf (O(log n)), remove the record. If the leaf becomes too empty, it merges with a neighbor or borrows records from an adjacent leaf.

  3. Update: Navigate to the leaf (O(log n)), change the data in place. If the key itself changes, it's a delete + insert.

The key point: You modify 1-2 nodes out of potentially millions. The rest of the tree stays untouched.

📝 Real-World Example: A Class Seating Chart

Imagine a classroom with 10 rows of benches, 5 students per row. Students are seated alphabetically.

Naive approach (flat file): All 50 students sit in ONE long row on the floor, alphabetically. A new student "Mohit" joins. Everyone from "N" to "Z" has to stand up and shift one seat to the right. That's 20+ students moving. 😩

B+ Tree approach (organized benches): Students sit on benches (leaf nodes), 5 per bench, alphabetically. Mohit joins? Find the right bench (the one with "Kumar, Laksh, Meera, Nisha"). There's space! Mohit sits down between Meera and Nisha. Done. Only 2 students on that bench shuffled slightly. Nobody else in the class moved. ✅

What if that bench is full? The teacher splits the bench into two: 3 students on the old bench, 3 on a new bench. The class map (non-leaf node) is updated to show the new bench. That's it. The rest of the class doesn't notice.

Technical Example

Inserting ID=37 into our B+ Tree:

Before:

              [30 | 60]
             /    |    \
    [10,20,30]  [40,50]  [70,80,90]
Enter fullscreen mode Exit fullscreen mode

Step 1: Navigate. 37 ≥ 30 and 37 < 60 → middle child [40, 50].

Step 2: Insert 37 → leaf becomes [37, 40, 50]. Still within capacity (max 3 entries). Done! ✅

              [30 | 60]
             /    |    \
    [10,20,30]  [37,40,50]  [70,80,90]
Enter fullscreen mode Exit fullscreen mode

What if the leaf was full? Say max capacity = 3, and the leaf was [40, 45, 50]. Inserting 37 creates [37, 40, 45, 50] — too many!

Split the leaf:

  • Left half: [37, 40]
  • Right half: [45, 50]
  • Middle key (45) is pushed up to the parent.
              [30 | 45 | 60]
             /    |    |    \
    [10,20,30]  [37,40] [45,50]  [70,80,90]
Enter fullscreen mode Exit fullscreen mode

Only 2 nodes were modified — the split leaf and its parent. The rest of the tree (potentially millions of nodes) stayed untouched.

📊 Image

Why Does This Matter for Developers?

Understanding insert performance helps you make better design decisions:

  • Auto-increment primary keys (1, 2, 3, 4...) are great for B+ Trees because new records always go to the END of the leaf chain. No splits needed in the middle.
  • Random UUIDs as primary keys cause inserts to land all over the tree, triggering frequent splits and rebalancing. This is why UUIDs can be 30-40% slower for write-heavy tables.
  • Bulk inserts (loading millions of rows at once) often bypass the normal B+ Tree insert path and use a special "bulk load" process that builds the tree bottom-up. That's why LOAD DATA INFILE in MySQL is way faster than millions of individual INSERT statements.

Topic 8: Range Queries — The B+ Tree's Superpower (Why Linked Leaf Nodes Matter)

Plain English Explanation

This is where B+ Trees truly dominate. A range query asks: "Give me everything between X and Y."

Here's how a B+ Tree handles it:

  1. Step 1: Use the tree to navigate to the first record in the range. This takes O(log n) — a few hops down the tree.
  2. Step 2: Now, simply walk the linked list of leaf nodes forward, reading record after record, until you pass the end of the range.
  3. Step 3: Stop.

You never need to go back up the tree. You never need to re-navigate. The horizontal chain of leaf nodes gives you a sorted highway through the data.

This is something a hash index CANNOT do. Hash indexes are great for "find this exact value" (point lookups) but useless for "find everything between A and B" because hashing destroys sorted order.

🎬 Real-World Example: Netflix "Continue Watching"

Imagine Netflix organizes all its shows in alphabetical order on a long digital shelf. You want to watch everything starting from "D" to "G" (Dark, Emily in Paris, Friends, Game of Thrones...).

Without linked leaf nodes: You'd search for "Dark" (go through the navigation tree). Then go BACK to the start and search for the next show. Then go back AGAIN and search for the next one. For 50 shows between D and G, that's 50 full tree traversals. 😩

With linked leaf nodes (B+ Tree): You search for "Dark" ONCE (tree traversal). Then you just slide right along the connected shelf: Dark → Derry Girls → Emily in Paris → Friends → Game of Thrones → stop (we've passed "G"). One search + a simple forward scan. ⚡

Technical Example

B+ Tree with linked leaves:

                    [50]
                   /    \
             [25]        [75]
            /    \      /    \
   [10,20] → [30,40] → [50,60] → [70,80] → [90,100]
     L1        L2         L3        L4         L5
Enter fullscreen mode Exit fullscreen mode

Query: SELECT * FROM products WHERE price BETWEEN 30 AND 70;

Step 1 — Tree navigation to find price = 30:

  • Root [50]: 30 < 50 → go left.
  • Node [25]: 30 ≥ 25 → go right child.
  • Arrive at Leaf L2 [30, 40]. Found the start! ✅

Step 2 — Walk the linked list:

  • L2: Read price=30 ✅, price=40 ✅
  • Follow link → L3: Read price=50 ✅, price=60 ✅
  • Follow link → L4: Read price=70 ✅, price=80 ❌ (80 > 70, stop!)

Result: Records with prices 30, 40, 50, 60, 70.

Total disk I/Os: 3 (tree traversal) + 3 (leaf reads for L2, L3, L4) = 6 disk reads.

Without the linked list, finding these 5 records would require 5 separate tree traversals = 5 × 3 = 15 disk reads. With the linked list: 6 reads. That's 60% fewer disk I/Os.

For large ranges (say, returning 10,000 records), the savings are even more dramatic.

📊 Image

Why Does This Matter for Developers?

Range queries are the most common query type in real applications:

Real Use Case SQL Query Range Type
Show last month's orders WHERE order_date BETWEEN '2024-11-01' AND '2024-11-30' Date range
Products in a price range WHERE price BETWEEN 500 AND 2000 Numeric range
Users who signed up recently WHERE created_at >= '2024-12-01' Open-ended range
Students with marks 60-80 WHERE marks BETWEEN 60 AND 80 Numeric range

Every BETWEEN, >, <, >=, <= in your SQL relies on this linked leaf node structure. If there's no index on the column, the database can't use a B+ Tree, and it falls back to a full table scan. Now you know exactly why indexes matter — and WHY they work!


🔗 SECTION 3 — How It All Connects (The Big Picture)

Let's tie everything together with one complete story.

The Story of FoodDash — A Food Delivery App Database

You're a developer building FoodDash, a food delivery app (like Swiggy or Zomato). Your app has 20 million restaurants across India. Each restaurant has: id, name, cuisine, rating, city, price_for_two.


🏗️ Day 1: The Naive Start

Your junior developer stores everything in a JSON file:

[
  {"id": 1, "name": "Sharma Ji Dhaba", "cuisine": "North Indian", "rating": 4.2, "city": "Delhi", "price_for_two": 400},
  {"id": 2, "name": "Dosa Corner", "cuisine": "South Indian", "rating": 4.5, "city": "Bangalore", "price_for_two": 300},
  ...
  {"id": 20000000, "name": "Pasta Palace", "cuisine": "Italian", "rating": 3.8, "city": "Mumbai", "price_for_two": 1200}
]
Enter fullscreen mode Exit fullscreen mode

A user in Bangalore searches for "South Indian restaurants rated above 4.0." The server reads all 20 million records, one by one, checking each. Takes 45 seconds. By then, the user has already switched to Swiggy. 😤


⚙️ Day 30: Migration to MySQL with B+ Trees

You migrate to MySQL (InnoDB engine). The database automatically creates a B+ Tree on the primary key (id). You also create indexes on rating and city:

CREATE INDEX idx_city ON restaurants(city);
CREATE INDEX idx_rating ON restaurants(rating);
Enter fullscreen mode Exit fullscreen mode

Now there are 3 B+ Trees:

  1. Primary key tree (clustered — leaf nodes contain full rows).
  2. City index tree (leaf nodes contain city values + pointers to full rows).
  3. Rating index tree (leaf nodes contain ratings + pointers to full rows).

Each tree is organized into 16 KB pages (InnoDB's default), with hundreds of keys per node.


🔍 Day 31: Point Lookup (Finding One Restaurant)

A user clicks on restaurant ID #12345678.

SELECT * FROM restaurants WHERE id = 12345678;
Enter fullscreen mode Exit fullscreen mode

The primary key B+ Tree:

  1. Root (cached in RAM — free!): 12345678 < 15000000 → go left.
  2. Internal node (1 disk read): 12345678 is between 12000000 and 13000000 → go to this child.
  3. Leaf node (1 disk read): Found! Return name="Biryani House", cuisine="Hyderabadi", rating=4.7.

2 disk reads. ~20 milliseconds. Not 45 seconds. 🚀


📊 Day 32: Range Query (Price-Based Search)

Marketing wants to know: "How many restaurants have a price_for_two between ₹200 and ₹500?"

SELECT COUNT(*) FROM restaurants WHERE price_for_two BETWEEN 200 AND 500;
Enter fullscreen mode Exit fullscreen mode

You create an index: CREATE INDEX idx_price ON restaurants(price_for_two);

The B+ Tree:

  1. Tree traversal to find the first restaurant at ₹200. (3 node reads)
  2. Walk the linked leaf nodes forward: ₹200, ₹210, ₹215... ₹490, ₹500. (Sequential reads)
  3. Stop at ₹501.

The linked leaf nodes made this possible without re-traversing the tree for each restaurant.


➕ Day 45: Inserting a New Restaurant

A new restaurant "Cloud Kitchen 99" registers. The database:

  1. Traverses the primary key B+ Tree to find the right leaf. (3 reads)
  2. Inserts the record. Leaf is full? Split it. (1-2 writes)
  3. Updates the parent node with the new key. (1 write)
  4. Also inserts into the city, rating, and price indexes. (3 more B+ Tree inserts)

Total: ~15-20 disk I/Os. Not 20 million. Just a handful of targeted operations.


🎯 The Complete Flow:

User opens FoodDash → Searches "Biryani in Hyderabad under ₹600"
        ↓
    SQL Query: WHERE city='Hyderabad' AND cuisine='Biryani' AND price < 600
        ↓
    MySQL picks the best B+ Tree index (city index)
        ↓
    Root node (cached in RAM) → "Hyderabad starts at this subtree"
        ↓
    Internal node (1 disk read) → "This range of Hyderabad restaurants"
        ↓
    Leaf node (1 disk read) → Finds matching restaurants
        ↓
    Walks linked leaf nodes → Grabs all Hyderabad restaurants
        ↓
    Filters by cuisine and price → Returns results
        ↓
    User sees results in 50ms → Orders biryani 🍛 → Happy customer!
Enter fullscreen mode Exit fullscreen mode

📊 Master Diagram


✅ SECTION 4 — Conclusion (What Did We Learn?)

  1. Naive file storage (sequential files) doesn't scale. Searching, inserting, updating, and deleting all require O(n) operations — practically unusable for production databases.

  2. B+ Trees solve this by organizing data into a multi-level tree structure with O(log n) search performance — even a billion records can be found in 3-4 disk reads.

  3. Each B+ Tree node fits exactly into one disk block (4-16 KB). This minimizes disk I/O — the slowest operation in computing.

  4. Non-leaf nodes are navigation signs. They contain only keys and pointers to guide searches. No actual data.

  5. Leaf nodes store all real data. Every actual database row lives at the bottom of the tree.

  6. Leaf nodes are linked together in a sorted chain. This makes range queries blazing fast — find the start, walk forward, stop at the end.

  7. Inserts, updates, and deletes are targeted. Only 1-2 nodes are modified (with occasional rebalancing). The rest of the tree stays untouched.

  8. B+ Trees excel at BOTH point lookups AND range queries. This dual capability is why they dominate over hash indexes for general-purpose database indexing.

  9. Almost every database you'll ever use is powered by B+ Trees — MySQL, PostgreSQL, SQLite, MongoDB (WiredTiger), Oracle, SQL Server — all of them.

  10. Understanding B+ Trees makes you a better developer. You'll write better queries, design better schemas, create smarter indexes, and debug performance issues like a pro.

🎉 You just learned one of the most fundamental concepts in database engineering — something many developers don't understand even after years of experience. You're ahead of the curve. Keep building, keep learning, and keep asking "WHY does this work?" You've got this! 💪


📋 SECTION 5 — Quick Revision Cheat Sheet

Concept One-Line Summary Real-Life Analogy
Naive File Storage Data stored line by line — every operation scans the whole file. O(n). Scrolling through 10,000 phone contacts one by one to find "Rahul."
B+ Tree Multi-level tree index — finds any record in 3-4 steps. O(log n). Supermarket signs: Section → Aisle → Shelf → Product.
4 KB Disk Block The minimum chunk a hard drive reads at once; B+ Tree nodes match this size. A pizza delivery bag — always carries a full load per trip.
Non-Leaf Node Upper nodes with only keys and pointers — no actual data. Just directions. Google Maps turn-by-turn directions — they guide you but don't feed you.
Leaf Node Bottom nodes storing ALL actual data rows. The actual shops in a mall — where you buy things.
Linked Leaf Nodes Leaf nodes connected in a sorted chain for fast sequential reading. A corridor connecting all shops on one floor — walk through without going upstairs.
O(n) Linear Scan Checking every record one by one. Slow and doesn't scale. Finding your friend by asking every person in a 10,000-person crowd.
O(log n) Search Each step eliminates 99%+ of the data. Fast even with billions of records. Guessing a number 1-1 billion in ~30 tries by halving each time.
Range Query Finding all records between value X and Y using the linked leaf chain. "Show me all T-shirts between ₹500 and ₹1000" — find the start, grab until the end.
Point Lookup Finding one exact record by its key. "Give me order #12345" — one direct lookup.
Rebalancing Tree auto-adjusts after inserts/deletes to stay evenly organized. A teacher redistributing students across benches when one gets too crowded.
Storage Engine Internal machinery deciding how data is physically stored and retrieved. A grocery store manager who organizes shelves and knows where everything is.

🔍 Frequently Asked Questions (FAQ) About B+ Trees

Q: Why do databases use B+ Trees instead of Binary Search Trees (BST)?
A: A BST has only 2 children per node, so it's very tall (many levels). A B+ Tree has hundreds of children per node, so it's very short (3-4 levels). Fewer levels = fewer disk reads = faster queries.

Q: Why B+ Tree instead of B-Tree?
A: In a regular B-Tree, data can live in ANY node (leaf or internal). In a B+ Tree, ALL data lives in leaf nodes only, and leaf nodes are linked. This makes range queries much faster because you can walk the leaf chain without going up and down the tree.

Q: Does MongoDB also use B+ Trees?
A: Yes! MongoDB's default storage engine (WiredTiger) uses B+ Trees for its indexes.

Q: Should I create an index on every column?
A: No! Each index is a separate B+ Tree that must be updated on every insert/update/delete. Too many indexes slow down writes. Only index columns that you frequently search, filter, sort, or join on.

Q: How do I check if my query is using a B+ Tree index?
A: Use EXPLAIN before your SQL query: EXPLAIN SELECT * FROM users WHERE email = 'test@gmail.com'; Look for type: ref or type: range (using index) vs type: ALL (full scan — no index used).


Happy learning! Now go run EXPLAIN on your SQL queries and see those B+ Trees in action. 🌳⚡

Top comments (0)