A strong answer
A sequential scan reads table pages in order while an index scan seeks through the index and then fetches scattered table rows, so the winner depends on selectivity — the fraction of rows the predicate keeps. When a query keeps 0.1% of a 10-million-row table, a few thousand index and heap page visits beat reading terabytes of pages. When it keeps 30 to 40%, chasing 3 million scattered heap pointers with random I/O loses to one ordered pass, and the planner correctly picks the scan even though an index exists. The crossover usually sits in the 5 to 10% range, shifting with row width, cache state, and storage.
An ordinary index scan also pays per-row extras that plans reveal: a heap fetch for every row whose columns are not in the index, plus a visibility check against concurrent versions. An index-only scan skips the heap fetch when all columns live in the index and the visibility map confirms the page is stable, which is why narrow projections over fresh statistics favor the index. Verify with EXPLAIN (ANALYZE, BUFFERS): compare estimated and actual rows at the scan node, read shared hits versus disk reads, and confirm whether the index path still visits the heap. Stale statistics are the common false signal — after a bulk load that doubles the table, estimates can be off by 10x until ANALYZE refreshes them.
Adding an index to force the index path is therefore a trade, not a fix: each new index adds a write on every insert, update, and delete plus permanent storage. When the workload genuinely needs a large fraction of rows, the scan is the efficient plan and the right answer is to accept it, batch the work, or narrow the query rather than index around it.
What the interviewer is listening for
- Selectivity driving the choice, with the 5 to 10% crossover stated as a range, not a law.
- Random heap fetches and visibility checks as the per-row tax on index scans.
- Reading estimated versus actual rows and buffer counts to confirm the plan.
- Stale statistics and non-indexable predicates as reasons a scan appears despite an index.
Common mistakes
- Calling every sequential scan a missing-index problem.
- Quoting plan cost units as milliseconds.
- Recommending an index without checking heap fetches or write-path cost.
- Running
EXPLAIN ANALYZEwithout noting that it executes the statement.