Indexes

An index is a data structure that lets a database find rows without reading the whole table — the difference between flipping to a book's index and reading every page. It's the highest-leverage performance tool a database gives you, and also the most misused: every index you add speeds up reads and slows down writes, so the skill is knowing exactly which ones earn their cost.

The storage half of this series covered how rows live on disk. Now we move to finding them efficiently. Without an index, answering WHERE email = 'x' means scanning every row in the table — a full table scan. An index is a secondary structure that maps column values to the rows that contain them, turning that scan into a direct lookup. This post covers how indexes work, the main kinds, and — most importantly — when they help and when they hurt.

The problem indexes solve

Consider a table of ten million users and the query SELECT * FROM users WHERE email = 'a@b.com'. With no index, the database must examine every row to find the match — ten million page-touches worth of work for one row. That’s O(n): cost grows linearly with table size, and it’s ruinous at scale.

An index on email changes the complexity. Because the index keeps email values sorted (in a B-tree, from the earlier posts), the database can navigate to the matching entry in a few page reads — O(log n) instead of O(n). For ten million rows that’s roughly a handful of reads versus ten million. Indexes are how a database stays fast as data grows; without them, every query degrades linearly with table size.

How an index points to rows

An index stores (indexed value → row location) entries, sorted by value. The “row location” detail differs by database and matters:

The practical upshot: a secondary-index lookup often costs two traversals — find the entry in the index, then fetch the actual row from the table (a “heap fetch” or primary-key lookup). That extra fetch is why some indexes help less than expected — and why covering indexes (below) are so valuable.

Kinds of indexes

Not all indexes are the same structure or serve the same query:

The cost of an index

Here is the discipline that separates good schema design from cargo-culting “add an index.” Indexes are not free — every index is a second data structure that must be kept in sync:

So the goal is not “index everything” but “index exactly what your read patterns need, and nothing more.” The trade is explicit: you buy faster reads with slower writes and more space. For read-heavy workloads that’s a great deal; for write-heavy tables, each index must justify itself.

When indexes don’t help (or hurt)

Indexes have failure modes worth knowing, because they explain a lot of “I added an index and nothing got faster”:

The recurring theme: an index is a bet that a given read pattern is frequent and selective enough to be worth the write and space cost. Confirm the bet with EXPLAIN (next post) rather than adding indexes on faith.

Practical guidance

Indexes are the bridge between the storage layer and the query layer. Having them isn’t enough — the database has to decide to use them, and weigh index access against scans and joins. That decision is the job of the query planner, the next post.

Key takeaways

Further reading

Sources & References

Index types and usage