Question presented to candidate:
"To list customers who have at least one order, one engineer writes SELECT DISTINCT c.* FROM customers c JOIN orders o ON ... and another writes WHERE EXISTS (SELECT 1 FROM orders o WHERE ...). The second is faster on our big tables. Why might EXISTS beat the JOIN, and is that always true?"
What a strong answer should cover:
- A JOIN returns one row per matching pair, so a customer with 40 orders becomes 40 rows (fan-out); DISTINCT or GROUP BY must then remove the duplicates
- EXISTS is a semi join: it needs only the first matching row per outer row, can stop there, and never duplicates the outer row
- With an index on the foreign key, a nested loop semi join reads one index entry per customer instead of all of them;
EXPLAIN ANALYZEshows this asrows=1versusrows=40per loop - Fan-out also silently inflates aggregates (
COUNT,SUM) when the join is only there to filter - It is not always faster: optimizers often plan
IN,EXISTSand even some joins the same way, and a JOIN is correct and fine when you need columns from the other table or the join is on a unique key
Clarifying questions expected:
- Do we need any columns from
orders, or only the customer rows? - Is there an index on
orders.customer_id, and roughly how many orders per customer?
Code / implementation expected: Yes β the JOIN with its duplicates, the EXISTS rewrite, and ideally the two plans side by side.
Schema used by the examples: