CTE materialization controls how PostgreSQL processes common table expressions (CTEs). It affects query speed and memory use.
CTE materialization behavior in PostgreSQL
WITH cte_name AS MATERIALIZED ( SELECT ... ) SELECT * FROM cte_name;
By default, PostgreSQL materializes CTEs, meaning it runs the CTE once and stores the result.
You can use MATERIALIZED or NOT MATERIALIZED to force or prevent this behavior.
WITH cte AS MATERIALIZED ( SELECT id, name FROM users WHERE active = true ) SELECT * FROM cte;
WITH cte AS NOT MATERIALIZED ( SELECT id, name FROM users WHERE active = true ) SELECT * FROM cte WHERE id > 10;
NOT MATERIALIZED is specified.WITH cte AS ( SELECT id FROM orders WHERE amount > 100 ) SELECT * FROM cte;
This query uses a materialized CTE to first get recent orders, then counts orders per customer.
WITH recent_orders AS MATERIALIZED ( SELECT order_id, customer_id FROM orders WHERE order_date > '2024-01-01' ) SELECT customer_id, COUNT(*) AS order_count FROM recent_orders GROUP BY customer_id;
Materialized CTEs can improve performance if the CTE is used multiple times.
Non-materialized CTEs allow PostgreSQL to optimize the query better but may run the CTE multiple times.
Use EXPLAIN to see how PostgreSQL handles CTEs in your queries.
CTE materialization controls if PostgreSQL stores intermediate results or inlines the CTE.
Use MATERIALIZED to force storing results, NOT MATERIALIZED to allow inlining.
Choosing the right behavior can help optimize query speed and resource use.