interviewpath
  • 0day streak
  • 10total XP
  • Level 1
0/7

Unit 6 · Databases · Lesson 4 of 10

Indexes, B+ trees, LSM trees and Bloom filters

Indexes decide whether a query touches a few pages or the whole table, and the storage engine’s core structure, usually a B+ tree or an LSM tree, decides how reads, writes and space trade off. This topic covers how those structures work and how to choose and reason about indexes for real workloads.
About 5 hFocus mode

Step 1: Learn the ideas

  • Primary (clustered) versus secondary indexes; heap versus index-organized tables
  • B+ tree structure, fanout, height and node splits
  • Composite keys, leftmost-prefix use, covering and partial indexes
  • Hash indexes and when ordering is not needed
  • Index concurrency: latch crabbing (awareness)
  • LSM trees: memtable, SSTables, levels and compaction
  • Read, write and space amplification; the RUM conjecture
  • Bloom filters and their false-positive math
  • Block-range summaries (BRIN, zone maps)
  • Learned indexes and the evidence about them (awareness)

Why it matters

Many database performance questions come down to an index: is there one the query can use, does the planner choose it, and what does it cost on writes? System-design interviews add the engine question, because a write-heavy event store and a read-heavy catalog want different structures. Knowing the mechanics lets you estimate instead of guess.

Core ideas

B+ trees. Inner nodes hold separator keys and child pointers; leaves hold keys with row pointers (or the rows themselves in an index-organized table) and are linked for range scans. With 8 KB pages and entries of roughly 16 bytes, fanout is in the hundreds, so a tree over 100 million keys is three or four levels deep and its upper levels stay in memory. A point lookup costs one page per level; a range scan costs the descent plus the matching leaves, plus one heap fetch per row when the index does not cover the query. An insert into a full leaf splits it and pushes a separator upward, which keeps the tree balanced. Concurrent access uses short latches with crabbing: release the parent once the child cannot split or merge.

Using indexes well. A composite index on (a, b, c) serves predicates on a, on a and b, and on all three, in that prefix order; put equality columns before the range column. An index-only scan answers from the index alone when it contains every needed column (PostgreSQL also consults its visibility map). For predicates that match a large fraction of rows a sequential scan is usually faster, because random heap fetches cost more than reading pages in order; the planner decides from statistics. Every index slows inserts and updates of the indexed columns. Hash indexes serve only equality; BRIN-style indexes store per-block-range minimum and maximum values and suit naturally ordered data such as append-only timestamps.

LSM trees. Writes go to a log and an in-memory sorted memtable. A full memtable is flushed as an immutable sorted file; background compaction merges files to discard overwritten values and deletion markers (tombstones). A read checks the memtable and then files from newest to oldest, so per-file Bloom filters and key-range metadata avoid most useless file reads.

Amplification. Write amplification is bytes written to storage per byte of user data; read amplification is pages or files touched per lookup; space amplification is storage used per byte of live data. Leveled compaction (one sorted run per level, each level about ten times larger than the previous) keeps reads and space low but rewrites each byte many times as data moves down the levels. Tiered compaction (several runs per level, merged together) writes less but reads and stores more. B+ trees update in place: low read amplification, but each small change dirties a whole page. The RUM conjecture frames the tradeoff: you can optimize two of read cost, update cost and memory (space) overhead, not all three.

Bloom filters. A bit array of m bits and k hash functions. Inserting a key sets k bits; a lookup that finds any of its bits unset proves the key is absent. With n keys the false-positive rate is about (1 − e^(−kn/m))^k, minimized near k = (m/n)·ln 2. Ten bits per key gives roughly a 1% false-positive rate. Standard Bloom filters do not support deletion and do not help range queries.

bits_per_key = 10, k = 7:  (1 - e^(-0.7))^7 ≈ 0.008

Common misconceptions

  • "An index always makes a query faster." For predicates that match many rows a sequential scan wins, and every index slows writes.
  • "B+ tree lookups are O(log n) random reads, so they are slow." The logarithm's base is the fanout: three or four levels with cached upper levels mean one or two real I/Os.
  • "Column order in a composite index does not matter." It decides which predicates can use the index and whether a sort can be avoided.
  • "LSM trees are always faster for writes." Their writes are cheap up front, but compaction consumes I/O and CPU continuously and can cause latency spikes and write stalls.
  • "Bloom filters give exact answers." They return false positives (never false negatives) and use memory proportional to the number of keys.
  • "Learned indexes replace B+ trees." Benchmarks show wins mainly for read-only, in-memory lookups; updates, worst cases and integration remain open.

How to approach it

Do the arithmetic once by hand: page size, entry size, fanout, height, then I/Os per query, and a Bloom filter's false-positive rate for two settings. Then run EXPLAIN in PostgreSQL on queries against a table with a composite index and watch the plan switch between index, bitmap and sequential scans as selectivity changes. In interviews, ask about the read/write mix, key distribution, point versus range queries and latency targets before choosing a structure, and quantify amplification instead of saying "LSM is write-optimized".

Suggested order

  1. 1Read CMU 15-445 Fall 2025 Lecture #08 notes (Indexes & Filters I) for B+ tree structure, operations and design choices.
  2. 2Read Lecture #09 notes (Indexes & Filters II) for Bloom filters, skip lists and tries, and Lecture #10 (Index Concurrency Control) for latch crabbing.
  3. 3Read DDIA Ch. 3 (Storage and Retrieval) for the comparison of log-structured and page-oriented engines.
  4. 4Read the RocksDB wiki pages Leveled Compaction and RocksDB Bloom Filter, noting how each setting moves read, write and space amplification.
  5. 5Read the PostgreSQL pages Index Types and Index-Only Scans and Covering Indexes, then run EXPLAIN on queries that use and ignore a composite index.
  6. 6Read the RUM conjecture paper (short) to organize the tradeoffs.
  7. 7Implement BusTub Project #2 (B+Tree) or the toy LSM store project, depending on the role you target.

Step 2: Check off what you can do

Tap each one you can genuinely do or explain. Each earns 10 XP.

Step 3: Go deeper

  • CMU 15-445/645 Intro to Database SystemsStart here

    Carnegie Mellon University Database Group

    Section: Fall 2025 Lecture #08: Indexes & Filters I (notes)

    B+ tree structure, operations and design decisions; Lectures #09 and #10 continue with filters and index concurrency.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Designing Data-Intensive ApplicationsStart here

    O'Reilly Media (author's book site)

    Section: Ch. 3: Storage and Retrieval

    Side-by-side explanation of hash indexes, SSTables and LSM trees, and B-trees, with their tradeoffs.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • RocksDB wiki: overview, compaction, Bloom filters and tuning

    RocksDB project (GitHub wiki)

    Section: Leveled Compaction

    How a production LSM engine organizes levels and why compaction settings change amplification; see also the Bloom filter page.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • PostgreSQL documentation: Transaction Isolation

    PostgreSQL Global Development Group

    Section: Index Types

    Which index types PostgreSQL offers (B-tree, hash, GiST, SP-GiST, GIN, BRIN) and which operators each supports.

    Open(opens in a new tab)Link responded, 5 Oct 2026
  • Designing Access Methods: The RUM Conjecture

    OpenProceedings (EDBT)

    Short paper framing read, update and memory overhead as a three-way tradeoff across access methods.

    Open(opens in a new tab)Link responded, 5 Oct 2026

Step 4: Practice

Start with the arithmetic drill: for 50 million rows, 8 KB pages and 24-byte entries, compute fanout, height and I/Os for a point lookup and a 1,000-row range scan, with and without a covering index. Then implement either BusTub Project #2 (B+ tree with concurrent access) or the toy LSM store; for the LSM store, report write amplification and runs probed per lookup for leveled and tiered merging with and without Bloom filters. If a newer 15-445 semester is running, its project pages may update the B+ tree assignment.

Record attempts on each problem’s page (+15 XP, +10 more when solved on your own).

Step 5: Test yourself

Answer each one out loud or on paper before you finish the lesson.

  1. Question 1Why do B+ trees store all values in the leaves and link them?
  2. Question 2When will PostgreSQL choose a sequential scan even though a matching index exists?
  3. Question 3Which predicates can use an index on (a, b) and which cannot?
  4. Question 4What makes a lookup for a missing key expensive in an LSM tree, and how do Bloom filters help?
  5. Question 5What is write amplification, and which compaction strategy has more of it?
  6. Question 6Why do deletes in an LSM tree initially increase space usage?

You’re done when you can

  • Compute B+ tree height and the I/O cost of point and range queries for given sizes without notes.
  • Design composite indexes for three given queries and justify the column order.
  • Explain leveled versus tiered compaction using read, write and space amplification in under three minutes.
  • Compute a Bloom filter configuration for a 1% false-positive rate and explain why it cannot serve range queries.

Finish the lesson

How confident do you feel?

Lesson complete!

+50 XP

Reviews will come up on the Practice tab so it sticks.

Unlocks next: Buffer pools, page layouts, row and column stores, Database benchmark and workload design

Your notes and study time

Log study time