SQL Practice Logo

SQLPractice Online

Window Functions vs CTEs: Performance

Module: Subqueries & CTEs

**Performance Benchmarks (1M rows):**

| Task | Window Function | CTE + Correlated Subquery | Winner |

|------|----------------|---------------------------|--------|

| Running total | 0.4s (O(N log N)) | 45s (O(N²)) | Window 100x faster |

| Ranking | 0.5s | 50s | Window 100x faster |

| Moving average | 0.6s | 60s | Window 100x faster |

| Data prep + analytics | 2s (CTE + Window) | N/A | Combined approach |

**Why Window Functions Are Faster:**

1. **Optimized algorithms**: Database engines have specialized algorithms for window functions

2. **Single pass**: Window functions often process data in one pass

3. **No correlated subqueries**: Avoid O(N²) complexity

4. **Efficient sorting**: Built-in sort optimization for ORDER BY in window

**When CTEs Are Better:**

1. **Readability**: Breaking complex query into steps

2. **Reusability**: Reference same subquery multiple times (with MATERIALIZED)

3. **Debugging**: Test each CTE independently

4. **Recursion**: Only way to handle hierarchical data

**Memory Considerations:**

- Window functions: Require sorting/partitioning (work_mem)

- CTEs: May materialize results (work_mem or temp disk)

- Combined: Both memory requirements apply

**Best Practices:**

1. **Use window functions for row-level analytics** (rankings, running totals)

2. **Use CTEs for query organization** (break complex logic)

3. **Combine both** (CTE for prep, window for analytics)

4. **Avoid correlated subqueries** when window function can do it

5. **Profile with EXPLAIN ANALYZE** to verify performance

Window functions are O(N log N), correlated subqueries are O(N²)

Running total: Window function 100x faster than CTE with correlated subquery

Ranking: Window function 100x faster than CTE with COUNT subquery

Moving average: Window function is only practical approach

Index columns used in PARTITION BY and ORDER BY

Limit window frame size when possible (ROWS BETWEEN 10 PRECEDING...)

Use ROWS instead of RANGE when possible (ROWS is faster)

Materialize CTEs when referenced multiple times

Combine window functions in single query (share sort operation)

Monitor work_mem for large window operations

Using CTE with correlated subquery instead of window function (100x slower)

Not understanding difference between RANK, DENSE_RANK, ROW_NUMBER

Forgetting ORDER BY in window function (undefined behavior)