What You'll Master Here
An index is a phone book. You can find everyone called Smith, and everyone called Smith whose first name starts with J. You cannot find everyone whose first name is John without reading the whole book.
An index is a sorted copy of some columns with a pointer back to the row. That one sentence explains almost everything an index can and cannot do: it can find rows by a prefix of its sorted key, and it cannot help with anything that is not a prefix.
This chapter is about the transactional side of SQL — the database behind an application, where a query looks up a handful of rows out of millions. It is the half of performance work a data engineer meets when they touch the source system rather than the warehouse.
Four ideas carry most of the value: selectivity decides whether an index is worth having, sargability decides whether a query can use one, the leftmost-prefix rule decides what a composite index covers, and every index has a write cost that nobody sees on a dashboard.
An index is a phone book. You can find everyone called Smith, and everyone called Smith whose first name starts with J. You cannot find everyone whose first name is John without reading the whole book.
The warehouse chapter teaches you to scan fewer bytes. This one teaches you to avoid scanning at all — and to recognise the queries where an index was present, correct, and unusable because of how the predicate was written.
- selectivity
- Distinct values as a share of rows. High selectivity means a lookup narrows the search a lot; a column with six values narrows almost nothing.
- sargable
- A predicate the engine can satisfy by seeking the index — from "Search ARGument ABLE". Wrapping the column in a function usually destroys it.
- leftmost prefix
- A composite index on (a, b, c) can serve queries on (a), (a, b) and (a, b, c) — and not on (b) or (c) alone.
- covering index
- An index that contains every column a query needs, so the engine never has to visit the table row at all.
Adding an index because a query is slow, without checking whether the predicate can use one. The index is built, maintained on every write, and never chosen by the planner. The query is exactly as slow and inserts are slower.
Check selectivity before proposing an index.
Read the predicate before blaming the index.
Count the write cost of every index you propose.
Everything here is about row-store databases — PostgreSQL, MySQL, SQL Server, Oracle. Columnar warehouses like Snowflake and BigQuery have no B-tree indexes at all; their equivalent is partitioning and clustering, which Chapter 10 covers. The contrast is the last section of this chapter.
An index is a sorted copy. Everything it can do follows from being sorted.
