Databases
Database Indexes: Make Product Queries Faster Safely
Database indexes improve product queries when they match real filters and ordering. Use query plans, measure write costs, and make migrations safe to release.
TL;DR — A database index is a maintained lookup structure that helps the database find or order matching rows without scanning the whole table. Add one to serve an observed query, confirm it with a query plan, and account for the extra storage and write work it creates. An index is evidence-driven product infrastructure, not a default reaction to slowness.
An index is often compared to a book’s index: it helps locate a topic without reading every page. The comparison is useful until it hides the cost. A database index must be updated whenever indexed data changes. Too few indexes leave important reads slow; too many make writes heavier and give the optimizer more choices to evaluate.
PostgreSQL’s index introduction and multicolumn index guide are authoritative starting points. They explain why a query’s filter, join, and ordering shape matters more than the name of an index type.
Start with the actual query
Ask which customer path is slow, what SQL it runs, how often it runs, and what rows it examines. A dashboard that lists a team’s newest open tickets might filter by team_id and status, then order by created_at DESC. A composite index can help only if it matches the query pattern and data distribution. An index on created_at alone may not help a tenant-scoped list.
Use the database’s explain facility before and after the change. A plan is evidence of the chosen path; execution statistics show whether the path improved the work that matters. Measure under representative data. A query that is fast with 100 rows can turn into a table scan problem at 10 million rows.
Respect order and selectivity
In a composite index, column order matters. Put equality conditions that narrow the set before the range or ordering condition when that matches the query. Do not convert that guideline into a ritual: the plan and real data decide. A low-cardinality column such as a boolean may be a poor standalone index, yet useful as part of a selective composite index or partial index.
Hypothetically, an inbox query filters to one workspace and unread messages, then orders by newest. An index designed for that filter and order can let API pagination advance through a cursor without repeatedly sorting the entire workspace. If the page also caches results, cache invalidation must still be correct after a message changes state.
The write side is part of the decision
Each insert, update, or delete may change an index. Indexing a frequently updated field can raise write latency and storage use. An index also needs a safe creation plan: some databases support concurrent creation; some migration paths lock more than a busy product can tolerate. Test the migration on realistic data and decide how to monitor it.
Avoid “index every foreign key” as a substitute for query review. Foreign-key-related queries may benefit, but the best index depends on how the relationship is joined, filtered, and deleted. The product risk is not an imperfect first index; it is an unmeasured change that slows writes across every customer.
Failure modes to surface
- Adding an index based on a query screenshot without its parameters or plan.
- Measuring only average duration and missing a slow tenant or wide date range.
- Fixing a report query with an index that makes transactional writes worse.
- Creating a duplicate or overlapping index without checking the existing catalog.
- Treating an index as permanent after the endpoint or access pattern changes.
Database connection pooling can expose a query that holds connections too long, while load testing proves whether the improvement holds when requests overlap. Both are better evidence than local intuition.
Acceptance checklist
- The change names the customer path and the exact measured query.
- Before and after plans and execution metrics are captured on representative data.
- The index supports the filter, join, and order actually used.
- Write cost, migration locking, and storage effects have an owner.
- A later review date or dashboard can show whether the index still earns its cost.
The founder decision is to buy speed only where a real user journey needs it. Database indexes make that speed durable when they are attached to a measured query and a clear workload.