Indexes in depth
How indexes speed reads and cost writes: B-tree indexes, composite order, covering indexes, clustered versus secondary, and how to pick them.
On the roadmap:Beginner · step 4: Databases 101
Lesson 2 of 5 · 13 min read · quiz · exercise
Why indexes exist
Without an index, finding rows means reading the whole table (a full scan). An index is a separate, sorted structure that maps column values to row locations, so the database can jump to the right rows. Most relational indexes are B-trees (see the storage engines lesson): shallow, sorted trees that make lookups and range scans fast.
The trade is always the same: faster reads, slower writes, more storage. Every insert, update and delete must also update each affected index.
What a B-tree index is good at
- Equality:
WHERE id = 42. - Ranges:
WHERE created_at >= ... AND created_at < .... - Sorting:
ORDER BY created_atcan be satisfied by index order, avoiding a sort. - Prefix matches:
LIKE 'abc%'(but notLIKE '%abc').
It does not help when the query hides the column in a function (WHERE LOWER(email) = ...) unless you index that expression, or when the column has so few distinct values that the index barely narrows anything.
Composite indexes and column order
A composite index on (a, b, c) is sorted by a, then b within each a, then c. It can be used for queries that use a leftmost prefix:
| Query uses | Can use the index? |
|---|---|
a | Yes |
a, b | Yes |
a, b, c | Yes |
b only | Not efficiently |
a, c | Partly (uses a) |
Ordering rules of thumb:
- Equality columns first, then the range or sort column last.
- Among equality columns, put the more selective (narrowing) one first if queries sometimes use only one of them.
- Design indexes around real queries, not columns in isolation.
Figure SDA-DDV-02-1 · How a composite index narrows a query · © forcsguy.com
Covering and included columns
If an index holds every column a query needs, the database reads only the index (an index-only scan) and skips the table. Some databases let you add non-key columns with INCLUDE, so the index is wide enough to cover a hot query without making the sort key longer.
Clustered versus secondary indexes
- A clustered index defines how the table rows themselves are stored: the table is the B-tree ordered by the key (InnoDB's primary key works this way). Range scans on the key are fast, and there is one per table.
- Secondary indexes are separate structures. In InnoDB a secondary entry stores the primary key, so a lookup is two steps (index, then clustered key). In PostgreSQL, the table is a heap and every index points at row locations.
Consequence: in a clustered design, a random primary key (like a random UUID) scatters inserts across the tree and fragments it; sequential or time-ordered keys insert at the end and stay compact.
Other index types (know they exist)
- Hash: equality only.
- Unique: enforces uniqueness and is also an index.
- Partial/filtered: index only the rows you query (
WHERE status = 'PENDING'), small and fast. - Full-text and inverted: search words in text.
- Spatial (GiST, R-tree): geographic queries.
- GIN / JSON indexes for arrays and JSON fields.
Choosing indexes
- Start from the slow or frequent queries (see the query optimisation lesson).
- Index columns used in
WHERE,JOINandORDER BY; always index foreign keys you join on. - Prefer few well-designed composite indexes to many single-column ones.
- Drop unused indexes (databases can report index usage); they only cost.
- Check the plan after creating one: databases ignore indexes they judge unhelpful.
Common mistakes
Indexing low-selectivity columns alone (a boolean); wrapping an indexed column in a function; leading wildcard searches; too many indexes on a write-heavy table; and forgetting that a type mismatch (comparing text to a number) can prevent index use.
Real-world reading
Related reading
- The Log-Structured Merge-Tree (paper)O'Neil et al. · UMass BostonPapers
- H3: Uber's Hexagonal Hierarchical Spatial IndexUber Engineering · UberCase Studies
- Use The Index, LukeMarkus Winand · use-the-index-luke.comCourses
- Amazon Aurora: Design Considerations for High Throughput Cloud-Native Relational Databases (paper)Verbitski et al. · Amazon Web ServicesPapers
Show 6 moreShow fewer
- How SQLite WorksSQLite team · SQLiteDocumentation
- MPH: Fast and Compact Immutable Key-Value Stores at IndeedIndeed engineers · IndeedCase Studies
- HaloDB: Embedded Key-Value Storage Engine at YahooYahoo engineers · YahooCase Studies
- PostgreSQL: Using EXPLAINPostgreSQL Global Development Group · PostgreSQLDocumentation
- FlockDB: Distributed Graph Database at TwitterTwitter engineers · TwitterCase Studies
- Performance Tuning on Quartz Scheduler at eBayeBay engineers · eBayCase Studies
Check your understanding
Question 1 of 3
0 correct so far
A composite index on (country, city) can serve which query best?
Go deeper
- Use The Index, Luke by Markus Winand: free and excellent
Topics covered in this lesson
Practise it: Reads that need an index
Everything below is already set up for this lesson: change the design, run the traffic, and see whether you meet the goal.
- 1The task
- 2Build and test
A heavy read workload hits one database. Indexes make each read cheap, but the load still needs somewhere to go.
Goal: Under 1% errors, database below 70% busy.
Beyond making each read cheaper, how do you spread reads and keep popular ones off the database?
Build it yourself
- B-tree labA balanced tree with many keys in each node, so finding any key takes only a few steps. Nodes split as they fill and the tree stays level.About 45 min · runs in your browser
- Keyset pagination labCompare offset paging with 'after this key' paging on a list that changes between requests.About 20 min · runs in your browser
Try it yourself
A query is: SELECT id, total FROM orders WHERE customer_id = ? AND status = 'PAID' ORDER BY created_at DESC LIMIT 20. Propose an index and explain the column order.
Click what a strong design here would need:
More in Building blocks
© 2026 forcsguy.com. Original lesson text and diagrams. Books and sites linked above belong to their authors.