Lesson 25 · Senior PostgreSQL backend engineering
Query shape and index choice
How senior engineers choose the right index for the real SQL, not for a generic idea of the table.
Your win: explain index choice the senior way: start from the real SQL, then justify whether you need a B-tree, composite, partial, covering, or expression index.
The problem: choosing indexes by column prestige
Many index mistakes happen before Postgres gets involved. A team decides that a column is important, adds an index, and later wonders why the planner still scans more rows than expected. The real question is not “what column do we care about?” It is “what work does this query ask the database to do?”
The pattern: think from the query outward
- B-tree for equality, range, ordering, and most everyday lookups
- Composite when the same column combination appears repeatedly in useful order
- Partial when only one subset of rows deserves indexing
- Covering / INCLUDE when reducing heap fetches matters on hot read paths
- Expression when the query consistently transforms the value before filtering
The senior move is to choose from these patterns after naming the query shape clearly, not before.
resource_path, soft-delete predicates like deleted_at IS NULL, trigram search, array overlap, and hand-written SQL builders all create very specific index needs instead of generic “index the table” needs.
Official index docs + Use The Index, Luke!
These are still the best sources for reasoning from SQL shape to index shape. Use the official docs for exact behaviour, and Luke for the practical query-first intuition.
Check yourself (from memory)
Q1. The first step in index choice is…
Sources. PostgreSQL Indexes; Use The Index, Luke!.