Medium java backend

EXISTS instead of IN for large subqueries

The 30 second answer

For a large subquery, EXISTS can stop at the first match per row, while a badly planned IN might build the whole list first. Modern PostgreSQL often plans both as the same semi-join, so I check EXPLAIN instead of assuming. The bigger trap is NOT IN with a subquery that can return nulls, because it silently returns no rows; NOT EXISTS avoids that.

The docs partly disagree with the original checklist here. In modern PostgreSQL, IN (subquery) and EXISTS are usually planned as the same semi-join, so swapping them often changes nothing. Check with EXPLAIN. The real trap is NOT IN: if the subquery returns any NULL, NOT IN returns NULL (no rows), and it can't become an anti-join. Use NOT EXISTS there.

SELECT * FROM customers c WHERE NOT EXISTS (SELECT 1 FROM orders o WHERE o.customer_id = c.id);
Sources (2)
  1. PostgreSQL 17: Subquery Expressions
  2. PostgreSQL wiki: Don't Do This, NOT IN