본문 바로가기
카테고리 없음

서브쿼리(Subquery) vs CTE(Common Table Expressions): 장단점과 성능 비교

by business27 2025. 8. 11.

SQL을 쓰다 보면, 하나의 쿼리 안에서 중간 계산 결과를 재활용하거나 복잡한 조건을 깔끔하게 정리해야 하는 순간이 많습니다. 이때 주로 선택하는 방법이 바로 서브쿼리(Subquery)공통 테이블 표현식(CTE)입니다. 둘 다 "쿼리 안에 또 다른 쿼리를 쓰는 방식"이지만, 구조와 활용 방법, 그리고 성능 면에서 차이가 존재합니다. 그 차이를 지금부터 한 번 알아보도록 하겠습니다!

 

 

 

서브쿼리(Subquery) vs CTE(Common Table Expressions): 장단점과 성능 비교

 

 

 

 

서브쿼리(Subquery)란?

서브쿼리는 말 그대로 쿼리 안에 포함된 또 다른 쿼리입니다. 보통 SELECT, FROM, WHERE 절 안에 들어가며, 하나의 쿼리 실행 중에 단 한 번만 평가되는 경우가 많습니다.

 

 

 

📌 서브쿼리 기본 구조

SELECT 컬럼명
FROM 테이블
WHERE 컬럼명 = (
SELECT MAX(컬럼명)
FROM 다른_테이블
);

 


1.1. 서브쿼리 종류

단일 행 서브쿼리 (Single-row Subquery) : 결과가 한 행만 나오는 서브쿼리입니다.

SELECT first_name, salary
FROM employees
WHERE salary = (
SELECT MAX(salary)
FROM employees
);

 

→ 급여가 가장 높은 직원 조회

 

 

다중 행 서브쿼리 (Multi-row Subquery) : IN, ANY, ALL 과 함께 사용합니다.

SELECT first_name
FROM employees
WHERE department_id IN (
SELECT department_id
FROM departments
WHERE location_id = 1700
);

 

→ location_id가 1700인 부서의 모든 직원 조회

 

 

 

상관 서브쿼리 (Correlated Subquery) : 외부 쿼리의 값을 참조하며 반복 실행됩니다.

SELECT e1.first_name, e1.salary
FROM employees e1
WHERE salary > (
SELECT AVG(salary)
FROM employees e2
WHERE e1.department_id = e2.department_id
);

 

→ 각 부서 평균 급여보다 더 많이 받는 직원 조회

 

 

1.2. 서브쿼리 장점

* 간단한 조건이나 한 번만 계산하는 값에 적합

* 기존 쿼리를 크게 변경하지 않고도 로직 추가 가능

* 대부분의 SQL 엔진에서 지원

 

1.3. 서브쿼리 단점

* 복잡해지면 가독성이 떨어짐

* 상관 서브쿼리는 반복 실행으로 인해 성능 저하 가능

* 재사용이 어려움 (같은 서브쿼리를 여러 번 쓰면 매번 실행됨)

 

 

 

 

CTE(Common Table Expressions)란?

CTE는 WITH 키워드로 선언하는 임시 결과 집합입니다. 이름을 붙여 쿼리 상단에 정의하고, 이후 메인 쿼리에서 마치 테이블처럼 재사용할 수 있습니다.

 

📌 CTE 기본 구조

WITH cte_name AS (
SELECT 컬럼명
FROM 테이블
WHERE 조건
)
SELECT *
FROM cte_name
WHERE 다른_조건;

 

 


2.1. CTE 예시

기본 CTE 사용

WITH HighSalary AS (
SELECT first_name, salary
FROM employees
WHERE salary > 10000
)
SELECT *
FROM HighSalary
WHERE first_name LIKE 'A%';

 

→ 급여가 10000 이상인 직원 중 이름이 A로 시작하는 사람 조회

 

 

다중 CTE

WITH DeptSalary AS (
SELECT department_id, AVG(salary) AS avg_salary
FROM employees
GROUP BY department_id
),
AboveAvg AS (
SELECT e.first_name, e.department_id
FROM employees e
JOIN DeptSalary ds
ON e.department_id = ds.department_id
WHERE e.salary > ds.avg_salary
)
SELECT *
FROM AboveAvg;

 

→ 각 부서 평균보다 급여가 높은 직원 조회

 

 

 

재귀 CTE (Recursive CTE)

WITH RECURSIVE EmployeeHierarchy AS (
SELECT employee_id, manager_id, first_name
FROM employees
WHERE manager_id IS NULL
UNION ALL
SELECT e.employee_id, e.manager_id, e.first_name
FROM employees e
JOIN EmployeeHierarchy eh
ON e.manager_id = eh.employee_id
)
SELECT *
FROM EmployeeHierarchy;

 

→ 직원-관리자 계층 구조 조회

 

 

2.2. CTE 장점

* 복잡한 쿼리를 단계별로 나누어 가독성 향상

* 같은 CTE 이름으로 여러 번 참조 가능 (일부 DBMS에서는 매번 실행될 수 있음)

* 재귀 쿼리 작성 가능

* 유지보수와 디버깅이 용이

 

 

 

2.3. CTE 단점

* 일부 DBMS에서 CTE는 항상 물리적 테이블처럼 실행되어 성능 손해 가능

* 재사용 시에도 매번 실행되는 경우가 있어 성능상 불리할 수 있음

* 인덱스를 직접 적용할 수 없음

 

[항목 서브쿼리 CTE]

가독성 짧은 쿼리엔 좋음, 복잡하면 난해 복잡한 쿼리를 단계별로 깔끔하게
재사용성 거의 없음 동일 CTE 이름을 여러 번 참조 가능
성능 상관 서브쿼리는 성능 저하 가능 DB 엔진에 따라 매번 실행되거나 캐시됨
지원 기능 모든 DB에서 가능 일부 DB에서 재귀 지원, 성능 차이 있음
적합한 상황 간단한 조건, 단일 계산 복잡한 로직, 단계별 계산, 재귀 구조

 

 

실무에서 선택 가이드

* 간단한 조건 → 서브쿼리

  예) 최대값, 최소값, 특정 조건 필터링

* 복잡한 다단계 로직 → CTE

   예) 여러 집계 결과를 결합, 재귀 계층 구조

* 성능 우선 → 실행 계획 확인
   EXPLAIN으로 실제 쿼리 계획을 분석하고, 필요시 인덱스 추가

 

 

마무리

서브쿼리와 CTE는 둘 다 "쿼리 안의 쿼리"라는 점에서 비슷하지만, 코드 구조, 재사용성, 성능 면에서 차이가 있습니다. 실무에서는 둘을 대체 관계로만 보지 말고, 상황에 맞게 병행해서 쓰는 것이 가장 좋습니다. 특히 대용량 데이터 환경에서는 실행 계획을 꼭 확인하고, 불필요한 반복 실행을 피하는 것이 핵심입니다.