CTE MATERIALIZED
PostgreSQL의 MATERIALIZED / NOT MATERIALIZED 이해하기
CTE(Common Table Expression)의 최적화 동작을 이해하면 쿼리 성능이 눈에 띄게 달라집니다.
1. CTE란?
CTE(Common Table Expression)는 SQL에서 WITH 절로 선언하는 임시 결과 집합입니다. 가독성을 높이고, 복잡한 쿼리를 단계별로 분리할 수 있다는 장점이 있습니다.
WITH sales_summary AS (
SELECT customer_id, SUM(amount) AS total FROM sales GROUP BY customer_id
)
SELECT *
FROM sales_summary
WHERE total > 10000;
이때 sales_summary는 마치 임시 테이블처럼 작동하지만, PostgreSQL에서는 내부적으로 CTE를 어떻게 처리하느냐에 따라 성능 차이가 크게 발생합니다.
2. PostgreSQL의 기본 동작
PostgreSQL 12 이전 버전에서는 CTE가 항상 Materialized 처리되었습니다.
즉, CTE를 한 번 계산해서 임시 메모리/디스크에 저장해두고, 이후 SELECT에서 재사용하는 구조입니다.
-- 기본적으로 MATERIALIZED로 동작
WITH cte AS (
SELECT * FROM orders WHERE status = 'PAID'
)
SELECT *
FROM cte
WHERE created_at > '2025-01-01';
이 방식은 “한 번 계산 → 여러 번 재사용”엔 유리하지만,
CTE가 한 번만 사용되는 경우에도 무조건 임시 테이블로 저장되므로 오히려 성능이 느려질 수 있습니다.
3. PostgreSQL 12 이후 - MATERIALIZED / NOT MATERIALIZED
PostgreSQL 12부터는 CTE의 처리 방식을 직접 제어할 수 있는 키워드가 추가되었습니다.
WITH cte AS MATERIALIZED (
SELECT * FROM orders WHERE status = 'PAID'
)
SELECT *
FROM cte
WHERE created_at > '2025-01-01';
MATERIALIZED
- CTE 결과를 미리 계산하고 임시 저장(캐싱)합니다.
- 동일 CTE를 여러 번 사용할 때 유리합니다.
- 단, 한 번만 참조된다면 불필요한 I/O 오버헤드가 생길 수 있습니다.
WITH cte AS NOT MATERIALIZED (
SELECT * FROM orders WHERE status = 'PAID'
)
SELECT *
FROM cte
WHERE created_at > '2025-01-01';
NOT MATERIALIZED
- 쿼리 옵티마이저가 CTE를 인라인(Inline) 처리합니다.
- 즉, 실제로는 “CTE가 없는 것처럼” 메인 쿼리에 합쳐져 실행됩니다.
- 한 번만 참조되는 경우 훨씬 빠릅니다.
4. 실행 계획 차이 (EXPLAIN으로 비교)
EXPLAIN WITH cte AS MATERIALIZED (
SELECT * FROM orders WHERE status = 'PAID'
)
SELECT *
FROM cte
WHERE created_at > '2025-01-01';
→ CTE가 별도 서브쿼리로 실행되고 결과를 임시 저장합니다.
EXPLAIN WITH cte AS NOT MATERIALIZED (
SELECT * FROM orders WHERE status = 'PAID'
)
SELECT *
FROM cte
WHERE created_at > '2025-01-01';
→ CTE가 메인 쿼리 내부로 합쳐져 실행됩니다.
조건절 최적화(WHERE, JOIN 등)가 그대로 적용되어 실행 비용이 낮아집니다.
5. 언제 어떤 걸 써야 할까?
- CTE를 여러 번 참조하거나 결과를 재사용해야 한다면 → MATERIALIZED
- CTE가 한 번만 사용되고, 단순히 가독성을 높이기 위함이라면 → NOT MATERIALIZED
- 쿼리 내부 최적화를 그대로 유지하고 싶다면 → NOT MATERIALIZED
요약
| 옵션 | 특징 | 적합한 경우 |
|---|---|---|
| MATERIALIZED | CTE를 임시 저장, 재사용 가능 | 같은 CTE를 여러 번 참조할 때 |
| NOT MATERIALIZED | 인라인 처리, 최적화 적용 | 단일 사용 시 성능 향상 |
읽어주셔서 감사합니다.
피드백이나 추가 궁금한 점은 댓글로 남겨주세요!
'Dev > [기타]개발' 카테고리의 다른 글
| [개인프로젝트] 대한민국 랜덤 여행 지역 뽑기 웹서비스 소개 (1) | 2025.12.26 |
|---|---|
| [Composite Index & Covering Index] 복합 인덱스와 커버링 인덱스의 개념 정리 (MySQL / PostgreSQL 기준) (0) | 2025.10.15 |
| C++ / OpenCV 번호판 인식 / OpenCV를 활용하여 자동차 번호판 위치 인식하기. (0) | 2025.09.30 |
| Mac 사용중인 포트 번호 확인하기 및 포트 삭제 (0) | 2025.03.25 |
| 도커, 컨테이너, 쿠버네티스트 이게 뭐지? (0) | 2025.02.04 |