CTE vs subquery vs view decision in SQL - Performance Comparison
When choosing between CTEs, subqueries, and views, it's important to understand how each affects the time it takes for a database to run a query.
We want to know how the work grows as the data gets bigger for each option.
Analyze the time complexity of these three ways to organize a query:
-- Using a CTE
WITH RecentOrders AS (
SELECT * FROM Orders WHERE OrderDate > CURRENT_DATE - INTERVAL '30 days'
)
SELECT CustomerID, COUNT(*) FROM RecentOrders GROUP BY CustomerID;
-- Using a subquery
SELECT CustomerID, COUNT(*) FROM (
SELECT * FROM Orders WHERE OrderDate > CURRENT_DATE - INTERVAL '30 days'
) AS RecentOrders GROUP BY CustomerID;
-- Using a view
-- Assume view RecentOrdersView is defined as:
-- SELECT * FROM Orders WHERE OrderDate > CURRENT_DATE - INTERVAL '30 days'
SELECT CustomerID, COUNT(*) FROM RecentOrdersView GROUP BY CustomerID;
Each method filters recent orders and counts them per customer.
Look at what repeats or loops over data:
- Primary operation: Scanning the Orders table to find recent orders.
- How many times: Once per query execution, regardless of method.
As the number of orders grows, the database must check more rows to find recent ones.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 row checks |
| 100 | About 100 row checks |
| 1000 | About 1000 row checks |
Pattern observation: The work grows roughly in direct proportion to the number of rows in Orders.
Time Complexity: O(n)
This means the time to run the query grows linearly with the number of rows in the Orders table.
[X] Wrong: "Using a view is always faster than a subquery or CTE because it is precomputed."
[OK] Correct: Views are just saved query definitions and usually run fresh each time, so they don't reduce the amount of work by themselves.
Understanding how these query structures affect performance helps you explain your choices clearly and shows you know how databases handle work as data grows.
"What if the CTE is referenced multiple times in the query? How would that affect the time complexity compared to a subquery or view?"
Practice
Solution
Step 1: Understand the purpose of CTEs
CTEs allow you to define temporary named result sets that can be referenced within a query, making complex queries easier to read and maintain.Step 2: Compare with other options
Views are permanent saved queries, subqueries are nested queries but can be harder to read, and indexes are for performance, not query structure.Final Answer:
Common Table Expression (CTE) -> Option AQuick Check:
Temporary query breakdown = CTE [OK]
- Confusing views as temporary structures
- Thinking subqueries improve readability as much as CTEs
- Assuming indexes help with query structure
Solution
Step 1: Recall CTE syntax
CTEs start with the keyword WITH, followed by the CTE name, AS, and a query in parentheses.Step 2: Check each option
WITH cte_name AS (SELECT * FROM table_name) SELECT * FROM cte_name; matches the correct syntax. CREATE VIEW cte_name AS SELECT * FROM table_name; is for views, C is a subquery, and D is invalid syntax.Final Answer:
WITH cte_name AS (SELECT * FROM table_name) SELECT * FROM cte_name; -> Option BQuick Check:
CTE syntax starts with WITH [OK]
- Using CREATE VIEW syntax for CTE
- Confusing subquery parentheses with CTE
- Using undefined keywords like DEFINE
WITH SalesCTE AS ( SELECT ProductID, SUM(Quantity) AS TotalSold FROM Sales GROUP BY ProductID ) SELECT * FROM SalesCTE WHERE TotalSold > 100;
Solution
Step 1: Analyze the CTE query
The CTE calculates total quantity sold per product by grouping Sales data by ProductID and summing Quantity.Step 2: Understand the main query filter
The main query selects rows from SalesCTE where TotalSold is greater than 100, so it returns products with sales over 100 units.Final Answer:
All products with total quantity sold greater than 100 -> Option DQuick Check:
CTE filters totals > 100 = correct output [OK]
- Thinking CTE is not executed or materialized
- Confusing GROUP BY usage
- Assuming syntax error without checking carefully
SELECT * FROM ( SELECT id, name FROM users ) AS user_sub WHERE user_sub.age > 30;What is the most likely cause of the error?
Solution
Step 1: Check subquery columns
The subquery selects only 'id' and 'name' columns, but the outer query filters on 'age' which is not selected.Step 2: Understand SQL column visibility
Since 'age' is not in the subquery result, the outer WHERE clause referencing 'age' causes an error.Final Answer:
The subquery does not include the 'age' column needed in WHERE -> Option CQuick Check:
Missing column in subquery causes error [OK]
- Forgetting to alias subquery
- Thinking subqueries can't be in FROM
- Moving WHERE inside subquery unnecessarily
Solution
Step 1: Understand the need for reuse
Reusing a complex query multiple times means you want a saved, reusable object in the database.Step 2: Compare features for reuse
Views are saved queries stored in the database and can be used repeatedly in different reports. CTEs are temporary and exist only during query execution. Subqueries are inline and not stored. Indexes improve performance but do not store queries.Final Answer:
Create a View because it saves the query in the database for easy reuse. -> Option AQuick Check:
Persistent reusable query = View [OK]
- Confusing CTEs as permanent
- Thinking subqueries are stored
- Misunderstanding indexes as query storage
Ready to prove it?
Pass the test and this pattern moves unknown
