All posts
Software Engineering

Database Indexing Internals: B-Trees, Cardinality, and Query Plans

Why indexes make reads fast and writes slow, how the planner chooses them, and how to read an EXPLAIN plan like a senior engineer.

SKSushan Khadka
June 2, 2026 (2mo ago)5 min read
Database Indexing Internals: B-Trees, Cardinality, and Query Plans — article by Sushan Khadka (namelessnerd)

An index is a trade: you pay on every write to make reads cheap. Add them blindly and you get a database that's slow in both directions — so the real skill is knowing which ones the planner will actually use.

Database Indexing Internals: B-Trees, Cardinality, and Query Plans - diagram by Sushan Khadka (namelessnerd)

What an index actually is

Strip away the mystique and an index is just a second copy of some of your data, kept sorted, with pointers back to the full rows. Because it is sorted, the database can binary-search it instead of scanning every row. That is the entire trick. Everything else — B+Trees, covering indexes, selectivity — is detail on top of "keep a sorted copy so you can search it fast."

The cost follows directly. Every INSERT has to slot the new key into the right sorted position in every index on the table. Every UPDATE to an indexed column has to move the entry. Five indexes on a table means five sorted structures to maintain on every write. This is why "just add an index" is never free, and why a write-heavy table with a dozen indexes can crawl.

Why B+Trees win

Most indexes are B+Trees: shallow, fan-out-heavy trees that turn a lookup into O(log n) instead of a full scan. Each node holds hundreds of keys, so even a billion-row table is only three or four levels deep — three or four disk reads to find any row. The leaves are sorted and linked in a chain, so range queries (WHERE price BETWEEN 10 AND 50), ORDER BY, and LIMIT come almost for free: find the start, then walk the leaf chain.

That structure explains what indexes are good at. Equality lookups, range scans, sorted output, and min/max all map onto "descend the tree, then walk the sorted leaves." It also explains what they are bad at — a WHERE name LIKE '%son' with a leading wildcard cannot use a B+Tree, because the sort order starts from the left and you have given it no left anchor to search from.

Not every index is a B+Tree

The B+Tree is the default, but the right index type depends on the query:

Reaching for the right type matters: trying to do full-text search or JSONB containment with a plain B+Tree is how you end up with an index the planner refuses to touch.

Two ideas that earn their keep

The selectivity trap

Here's what trips people up: an index on a low-cardinality column — think status with three values — often gets ignored. The planner estimates that matching rows are a big chunk of the table, decides random index lookups scattered across the disk cost more than one sequential read of the whole table, and picks a Seq Scan. It's not broken; it's doing math. Random I/O is expensive; sequential I/O is cheap; past roughly 5–10% of a table, scanning wins.

Indexes pay off on high-selectivity predicates that return a small slice — a user_id, an email, an order number. The mental test: "if I ran this filter by hand, would it hand me a handful of rows or half the table?" A handful means index; half the table means the planner is right to scan. A partial index (WHERE status = 'pending') rescues the low-cardinality case when you only ever query one value — it indexes just those rows and stays tiny.

Read the plan, don't guess

Stop theorizing about performance and ask the database directly:

EXPLAIN ANALYZE
SELECT * FROM orders WHERE customer_id = 42;

EXPLAIN shows the planner's intended plan; adding ANALYZE actually runs it and shows real timings and row counts. Read it inside-out — the most indented node runs first — and look for:

The plan is ground truth — your intuition isn't. I have watched engineers argue for an hour about why a query is slow when 30 seconds of EXPLAIN ANALYZE would have pointed straight at a missing index or a stale statistic.

The takeaway

Read more posts