Scenario · Query Performance
Partial index opportunity
A sandboxed PostgreSQL incident — investigate with your own tools, submit a fix, and get deterministic Detect / Fix / Trap scoring.
L3 · 10–15 min · runs locally in Docker
Launch
Start this scenario
Boot it in a real PostgreSQL sandbox and investigate with psql, EXPLAIN and pg_stat_statements.
ride postgres start stage-01/10-partial-index-opportunityPart of these paths
Show the postmortem & investigation hints spoilers
Partial index opportunity Type: incident simulation · Topic: Query Performance · Level: L3 · Duration: 10–15 min Launch: ride postgres start stage-01/10-partial-index-opportunity POSTMORTEM (root cause · how it was found · the fix · lesson) Root cause: the dashboard query only ever looks at recent *failed* orders — a small, hot subset — but there was no index, so it did a Seq Scan of the whole table every time. Indexing all rows (or indexing the low-selectivity status column) would be wasteful; the query never needs the other 98%. How it was found: EXPLAIN (ANALYZE) showed a Seq Scan; the filter status='failed' matches only ~2% of rows — a textbook partial-index opportunity. The fix: CREATE INDEX idx_orders_failed_recent ON orders (tenant_id, created_at DESC) WHERE status = 'failed'; The index only stores the failed rows, so it's small and cache-friendly, and the planner uses it because the query's `status = 'failed'` predicate implies the index's WHERE clause. Lesson: when a query always targets a narrow predicate, a partial index beats a full one — smaller, cheaper to maintain, and just as fast for that path. Don't reach for a big general index (or a low-selectivity status index) when a partial index fits the access pattern. INVESTIGATION HINTS (the staged path to diagnose and fix) 1. Check how much of the table the query actually touches: it only ever looks at status = 'failed', which is a tiny slice. A full index on all rows would be large and mostly wasted. 2. EXPLAIN (ANALYZE) the query — a Seq Scan to find a small hot subset is the signal for a partial index. 3. Create a partial index: CREATE INDEX ... ON orders (tenant_id, created_at DESC) WHERE status = 'failed'. It's small, hot, and the planner uses it because the query's status filter matches the index predicate.