Question presented to candidate:
"You run EXPLAIN ANALYZE on a slow query against a 10-million-row orders table and the plan says Seq Scan. Walk me through how you decide whether that is actually wrong, how you find the cause, and how you fix it safely in production."
What a strong answer should cover:
- A Seq Scan is not automatically a bug: compare the rows the query returns with the rows in the table, and the planner estimate (
rows=) with the actual count; for a large share of the table a Seq Scan is the cheapest plan - The signal that an index is missing or unusable: very few
actual rowsbut a hugeRows Removed by Filterand a buffer count close to the whole table - The common causes: no index on the filtered column; an index that cannot be used because the column is wrapped in a function, cast or wrong-typed literal (non-sargable predicate), a leading-wildcard
LIKE, anORacross columns, the wrong column order in a composite index; stale statistics that make the planner over-estimate the matching rows - The fixes: a matching (or expression / composite / partial) index built with
CREATE INDEX CONCURRENTLY, rewriting the predicate so the bare column is compared,ANALYZEand a higher statistics target, then re-runningEXPLAIN (ANALYZE, BUFFERS)to prove the change - Using
SET enable_seqscan = offonly as a diagnostic in one session, never as the fix; checking cost settings such asrandom_page_coston SSD storage
Clarifying questions expected:
- How many rows does the query return, and how many rows does the table have?
- Is this query new or did it get slow recently (data growth, a deploy, a bulk load)?
- Can we add an index on this table online, and how write-heavy is it?
Code / implementation expected: Yes — read the plan, create the right index (or rewrite the predicate, or ANALYZE) and show the plan change.
Schema used by the examples: