SQL-Engineering-Handbook

Topic 08: Subquery Rewrites & Query Rewrite Lab

A Subquery Rewrite is a systematic structural refactoring of a SQL statement that yields identical relational output while altering its internal Abstract Syntax Tree (AST) to unlock faster physical execution plans. This document serves as an engineering catalog and lab for transforming $\mathcal{O}(N \times M)$ nested loop subqueries into $\mathcal{O}(N + M)$ set-based joins.


Learning Objectives


Engineering Context

Database performance tuning in enterprise web platforms frequently requires refactoring legacy subqueries written by ORMs or junior developers. In many cases, refactoring an un-optimized subquery into a join or window function reduces query execution time from 45 seconds to 12 milliseconds without changing hardware or adding new indexes.


Business Context

In high-concurrency transactional platforms (e.g. Stripe, Uber, Airbnb), un-optimized subqueries degrade connection pool availability and cause CPU thread starvation. Query rewrites preserve strict business logic while ensuring sub-second response times under peak SLA loads.


Mental Model

Un-Optimized Subquery (AST)        Optimized Refactored Query (AST)
 ┌─────────────────────────┐        ┌─────────────────────────┐
 │ SubPlan                 │        │ Hash Semi / Anti Join   │
 │ Executed once per row   ├───────►│ Executed in 1 pass      │
 │ Complexity: O(N × M)    │        │ Complexity: O(N + M)    │
 └─────────────────────────┘        └─────────────────────────┘

Theory

Relational algebra transformations prove that for any inner relation $S$ and outer relation $R$: \(\sigma_{A \in \pi_A(S)}(R) \equiv R \ltimes_{R.A = S.A} S\)

Unnesting pulls the inner subquery out of the WHERE predicate and converts it into a top-level join node in the query plan tree.


SQL & Query Rewrite Lab

Lab Case 1: Correlated Aggregate Subquery $\longrightarrow$ Derived Table Pre-Aggregation

Original Query (Correlated SubPlan)

SELECT 
    e.emp_id,
    e.emp_name,
    e.dept_id,
    e.hire_date
FROM employes e
WHERE e.hire_date = (
    SELECT MIN(sub.hire_date) 
    FROM employes sub 
    WHERE sub.dept_id = e.dept_id
);

Execution Plan (Original)

Seq Scan on employes e  (cost=0.00..62.50 rows=3 width=40) (actual time=0.045..0.215 rows=5 loops=1)
  Filter: (hire_date = (SubPlan 1))
  SubPlan 1
    ->  Aggregate  (cost=1.22..1.23 rows=1 width=4) (actual time=0.003..0.003 rows=1 loops=50)
          ->  Seq Scan on employes sub  (cost=0.00..1.22 rows=2 width=4) (actual time=0.001..0.002 rows=2 loops=50)
                Filter: (dept_id = e.dept_id)

Refactored Query (Derived Table Join)

SELECT 
    e.emp_id,
    e.emp_name,
    e.dept_id,
    e.hire_date
FROM employes e
JOIN (
    SELECT dept_id, MIN(hire_date) AS min_hire
    FROM employes
    WHERE dept_id IS NOT NULL
    GROUP BY dept_id
) d_min ON e.dept_id = d_min.dept_id AND e.hire_date = d_min.min_hire;

Execution Plan (Refactored)

Hash Join  (cost=2.45..5.80 rows=4 width=40) (actual time=0.048..0.095 rows=4 loops=1)
  Hash Cond: ((e.dept_id = d_min.dept_id) AND (e.hire_date = d_min.min_hire))
  ->  Seq Scan on employes e  (cost=0.00..2.00 rows=50 width=40) (actual time=0.005..0.010 rows=50 loops=1)
  ->  Hash  (cost=2.36..2.36 rows=4 width=12) (actual time=0.025..0.026 rows=4 loops=1)
        ->  HashAggregate  (cost=2.25..2.36 rows=4 width=12) (actual time=0.021..0.024 rows=4 loops=1)
              Group Key: employes.dept_id

Performance Difference

Engineering Reasoning

Pre-aggregating the subquery table into a derived view forces the query planner to calculate department minimums once using an in-memory hash aggregate table, completely eliminating row-by-row SubPlan iterations.


Lab Case 2: Projected Scalar Subquery $\longrightarrow$ Window Function

Original Query (Projected SubPlan)

SELECT 
    e.emp_id,
    e.emp_name,
    e.salary,
    (SELECT AVG(sub.salary) FROM employes sub WHERE sub.dept_id = e.dept_id) AS dept_avg_salary
FROM employes e;

Refactored Query (Window Function)

SELECT 
    e.emp_id,
    e.emp_name,
    e.salary,
    AVG(e.salary) OVER (PARTITION BY e.dept_id) AS dept_avg_salary
FROM employes e;

Performance Difference


Execution Order

  1. Inner Pre-Aggregation: Derived tables or window partitions pre-calculate aggregate metrics.
  2. Hash Build: Inner key-value pairs are hashed into RAM.
  3. Outer Probe: Outer relation streams tuples, executing single-pass hash lookups.

Optimizer Behaviour

Optimizers automatically pull up simple inline views and unnest IN/EXISTS subqueries. However, when complex aggregations or HAVING clauses are present inside a correlated subquery, manual refactoring is required to force decorrelation.


Execution Plan

See the detailed EXPLAIN (ANALYZE, BUFFERS) tree breakdowns in the SQL & Query Rewrite Lab section above.


Performance Notes

Refactoring correlated subqueries to pre-aggregated joins changes algorithmic time complexity from $\mathcal{O}(N \times M)$ to $\mathcal{O}(N + M)$. Ensure work_mem is tuned appropriately for large HashAggregate operations.


Cross Database Notes

Engine Automatic Decorrelation Window Function Support Derived Table Inlining
PostgreSQL 16+ Partial (Unnests IN/EXISTS). Fully supported (OVER). Inlines non-recursive CTEs/Views.
MySQL 8.0+ Materializes IN subqueries. Fully supported (8.0+). Merges derived tables.
SQL Server 2022 Transformed via APPLY. Fully supported. Transformed via optimizer tree.
Oracle 23c Complex View Merging. Fully supported. View merging engine.

Edge Cases


Failure Cases


Common Mistakes

-- ❌ BAD: Refactored to INNER JOIN without handling inner duplicates (Duplicates outer rows!)
SELECT e.emp_name 
FROM employes e 
JOIN departments d ON e.dept_id = d.dept_id;

-- ✅ GOOD: Retain EXISTS or use pre-aggregated JOIN
SELECT e.emp_name 
FROM employes e 
WHERE EXISTS (SELECT 1 FROM departments d WHERE d.dept_id = e.dept_id);

Production Notes


Real Company Example

Netflix: Title Viewing Rank Calculation

Netflix refactored viewing history rank subqueries into Window Functions, reducing user homepage load latencies from 3.2 seconds to 85 milliseconds during peak global traffic.


Engineering Tips


Interview Questions

Q1: Why does refactoring a correlated aggregate subquery to a Derived Table Join improve performance?

Difficulty: Senior
Expected Answer: A correlated subquery executes as a SubPlan once per outer row ($\mathcal{O}(N \times M)$). A Derived Table pre-aggregates the inner table once in memory ($\mathcal{O}(M)$) and joins it using a single-pass Hash Join ($\mathcal{O}(N + M)$).
Reasoning: Changing algorithmic time complexity from quadratic/multiplicative to linear guarantees scalability.
Common Wrong Answers: “Joins are always faster than subqueries because database indexes only work with joins.” (False: indexes work with subqueries too).
Follow-up Questions: How do you handle ties when joining on aggregate minimum values?


Practice

See 15_PRACTICE_PROBLEMS.md for 15 enterprise practice problems.


Summary

Rewrite Pattern Original Operator Refactored Operator Scalability Impact
Correlated Aggregate SubPlan Hash Join $\mathcal{O}(N \times M) \rightarrow \mathcal{O}(N + M)$
Projected Scalar SubPlan WindowAgg $\mathcal{O}(N \times M) \rightarrow \mathcal{O}(N \log N)$
NOT IN SubPlan / Filter Hash Anti Join Fixes silent NULL data loss