※ PostgreSQL: ANSI SQL: Comparison of CTE(Common Table Expression) and Subquery.
안녕하세요. 듀스트림입니다. 새해 복 많이 받으세요.
2025년의 첫 포스팅은 많이 사용되는 CTE(Common Table Expression)와 서브쿼리(Subquery)의 차이를 살펴보도록 하겠습니다.
1. CTE와 서브쿼리의 차이점
항목 | CTE | 서브쿼리 |
가독성 | 직관적 | 복잡한 구조일수록 어려워짐 |
재사용성 | 동일 CTE를 여러 번 참조 가능 | 재사용 불가 |
디버깅 용이성 | 각 CTE 단위로 결과를 쉽게 디버깅 가능 | 서브쿼리 단위로 디버깅하기는 어려움 |
성능 | 반복 참조가 필요한 경우 우수 | 단순 필터링, 작은 데이터 셋, 중첩 구조가 단순한 경우 우수 |
코드 구조 | 명시적으로 분리된 블록 구조 | 메인 쿼리 내에 포함되어 복잡해질 수 있음 |
사용 목적 | 반복적 참조 및 복잡한 쿼리 단순화 | 단일 작업 수행에 적합 |
2. 특징
CTE | 서브쿼리 |
1. 임시 데이터 집합: 쿼리 실행 중에만 존재 2. 가독성: 복잡한 쿼리를 논리적 단계로 나눔 3. 재귀 지원: 재귀적 데이터를 쉽게 처리 가능 4. 구조화: SQL 코드의 계층적 구조를 지원 |
1. 중첩 가능: 메인 쿼리의 SELECT, FROM, WHERE 등에서 사용 가능 2. 일회성: 서브쿼리는 한 번 사용 후 재참조 불가 3. 성능: 경우에 따라 직접 최적화 가능 4. 단순 작업: 간단한 조건 필터링이나 계산 작업에 유용 |
3. 장점
CTE | 서브쿼리 |
1. 복잡한 쿼리를 논리적 단계로 나눠 가독성 향상 2. 동일 테이터를 반복 참조 가능 3. 재귀적 데이터 처리에 적합 4. 유지보수 용이(블럭 단위로 코드를 쉽게 수정 가능) |
1. 간단한 작업에 적합(코드 작성이 상대적으로 쉬움) 2. 독립적인 데이터 집합으로 제한된 문맥에서 사용 가능 3. 중첩 조건에 따른 필터링이나 계산에 적합 |
4. 주의점
CTE | 서브쿼리 |
1. 성능: CTE는 항상 실행 시 계산되므로 대규모 데이터 셋에서는 성능 저하가 있을 수 있음 2. 임시성: 쿼리 실행 후 데이터 휘발됨 |
1. 복잡성 증가 : 중첩이 많아지면 코드 가독성이 매우 낮아짐 2. 성능 이슈: 필요 이상으로 중첩 시 성능 저하 3. 재사용성 부족: 동일 데이터를 반복해서 사용할 경우 비효율적 |
5. CTE 문법
▸ 기본 문법
WITH CTE_NAME AS (
SELECT column1, column2
FROM table_name
WHERE condition
)
SELECT * FROM CTE_NAME;
▸ 활용 예시
-- 데이터 정규화(반복 계산 작업 단순화)
WITH Total_Sales AS (
SELECT salesperson_id, SUM(sales) AS total_sales
FROM sales_data
GROUP BY salesperson_id
)
SELECT salesperson_id, total_sales
FROM Total_Sales
WHERE total_sales > 100000;
-- 재귀적 데이터 처리(계층 구조 탐색)
WITH RECURSIVE OrgChart AS (
SELECT employee_id, manager_id, 1 AS level
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, oc.level + 1
FROM employees e
INNER JOIN OrgChart oc
ON e.manager_id = oc.employee_id
)
SELECT *
FROM OrgChart;
6. 서브쿼리 문법
▸ SELECT 절에서 서브쿼리(Scalar Subquery)
→ 스칼라 서브쿼리에 의해 나오는 결과는 '하나의 행'
SELECT employee_id,
(SELECT department_name
FROM departments
WHERE departments.department_id = employees.department_id) AS dept_name
FROM employees;
▸ FROM 절에서 서브쿼리(Inline View)
→ 인라인 뷰는 하나의 임시 테이블
→ 메인 쿼리에서는 인라인 뷰에서 SELECT한 컬럼만 사용 가능
SELECT employee_id, department_name
FROM (SELECT employee_id, department_id FROM employees) emp
JOIN departments
ON emp.department_id = departments.department_id;
▸ WHERE 절에서 서브쿼리
→ WHERE 절에서 사용하는 서브쿼리 = 서브쿼리
-- 단일행 서브쿼리(서브쿼리의 결과가 1개 행)
SELECT employee_id, first_name
FROM employees
WHERE department_id = (SELECT department_id
FROM departments
WHERE department_name = 'Sales');
-- 복수행 서브쿼리(서브쿼리의 결과가 여러 행)
SELECT employee_id, first_name, department_id
FROM employees
WHERE department_id IN (SELECT department_id
FROM departments
WHERE department_name IN ('Sales', 'Marketing'));
7. PostgreSQL에서의 CTE
CTE는 WITH 키워드로 정의되며, 두 가지 방식으로 동작합니다.
- MATERIALIZED:
- CTE는 임시 테이블로 처리됩니다.(한 번 계산되고 결과가 저장된 뒤 최종 쿼리에 참조됨)
- CTE 결과는 쿼리 실행 중 한 번만 계산되고, 이후 재사용될 때 다시 계산되지 않습니다.
- 반복 참조가 필요한 경우 효율적입니다.
- NOT MATERIALIZED:
- CTE는 인라인 처리되어 서브쿼리처럼 동작합니다.(바로 인라인 처리됨)
- 반복 참조가 없거나, 데이터가 작을 때 유리합니다.(재참조 시 다시 계산됨)
- PostgreSQL 12 이후로 기본 CTE 동작은 NOT MATERIALIZED로 최적화됩니다.
+ WITH RECURSIVE: 재귀적 데이터 처리를 위해 사용(재귀적 호출은 인라인 처리 방식으로 동작)
새해에는 모두 더 행복하셨으면 좋겠습니다-!
그럼 오늘은 여기까지 :)
'SQL' 카테고리의 다른 글
PostgreSQL(ANSI SQL): LEFT JOIN ... IS NULL과 NOT EXISTS의 차이 (0) | 2024.12.23 |
---|---|
PostgreSQL 쿼리 튜닝: LEFT JOIN ... IS NULL → NOT EXISTS로 변환, 인덱스 활용 (1) | 2024.12.20 |
PostgreSQL 쿼리 튜닝: INSERT INTO → CTAS로 5배 성능 향상 (2) | 2024.12.13 |