[SQLD 10화] 서브쿼리(Subquery)의 종류별 문법과 실무 가독성과 성능에 미치는 영향 분석 (SQLD, 직장인 SQL)

1. 쿼리 안의 작은 쿼리: 서브쿼리의 본질과 필요성

9화에서 우리는 기준 테이블의 모수를 온전히 보존하면서 다차원 데이터 결합을 구현하는 LEFT OUTER JOIN의 문법 구조와, WHERE 절 필터 배치 실수로 인한 데이터 결합 누락 현상을 예방하는 방안을 살펴보았습니다. 이처럼 테이블 간의 조인(Join) 구조를 마스터하고 나면, 분석가는 한 단계 더 나아가 단 한 줄의 실행 명령어로 복잡한 다단계 연산을 한 번에 처리해야 하는 고난도 과제와 마주하게 됩니다.

현업 실무에서는 “전체 평균 구매 금액보다 더 많은 금액을 지출한 우수 고객의 명단을 추출해 달라”거나 “임원 보고용 요약 장표 옆에 전사 기준 메트릭 수치를 나란히 붙여달라”는 식의 요청이 자주 들어옵니다. 이러한 조건들을 해결하려면 ‘전체 평균을 구하는 연산’이 선행되어야 하고, 그 결과값을 바탕으로 ‘다시 대소 비교 필터링을 수행하는 연산’이 유기적으로 이어져야 합니다.

이처럼 하나의 쿼리 문장(Main Query) 내부에 또 다른 가상의 조회를 중첩하여 집어넣는 형태를 SQL에서는 ‘서브쿼리(Subquery)’라고 부릅니다. 본 연작 시리즈는 기업형 대용량 데이터 처리에 널리 쓰이는 테라데이터 SQL 환경을 기준으로 위치별 서브쿼리 문법과 실무 활용법을 설명하겠습니다.

2. 서브쿼리가 위치하는 공간에 따른 3가지 종류별 문법

서브쿼리는 메인 쿼리의 어느 절(Clause)에 삽입되느냐에 따라 크게 세 가지 유형으로 분류됩니다. 각 유형은 문법적 규칙과 최종적으로 반환하는 데이터의 형태가 다르므로 이를 정확히 매칭하여 구사하는 것이 중요합니다.

1) 스칼라 서브쿼리 (Scalar Subquery): SELECT 절에 위치

대표적으로 SELECT 절에서 하나의 칼럼처럼 단일값을 반환하는 형태를 스칼라 서브쿼리라고 합니다.

  • 문법적 규칙: 반드시 단 하나의 행(Row)과 단 하나의 열(Column), 즉 단 하나의 단일값(Single Value)만을 반환해야 하는 엄격한 규칙을 가집니다. 만약 두 개 이상의 행이나 칼럼이 반환되면 데이터베이스 엔진은 실행 오류를 발생시킵니다.
-- 메인 테이블 조회 시 옆에 전사 총 매출액을 가상 칼럼으로 나열하는 예시
SELECT 
    A.CUST_NO
  , A.PURCHASE_AMT
  , (SELECT SUM(SUB.PURCHASE_AMT) FROM DW_MART.DAILY_SALES SUB) AS TOTAL_GLB_AMT
FROM 
    DW_MART.CUSTOMER_SALES_MART A;

2) 중첩 서브쿼리 (Nested Subquery): WHERE 절에 위치

WHERE 절에 삽입되어 메인 쿼리의 행들을 걸러내는 필터(Filter) 조건의 부품으로 작동하는 서브쿼리입니다.

  • 문법적 규칙: 반환하는 데이터의 형태에 따라 단일 행 연산자(=, >, < 등) 또는 다중 행 연산자(IN, ANY, ALL 등)와 유기적으로 결합하여 사용해야 문법적 에러를 막을 수 있습니다.

3) 인라인 뷰 (Inline View): FROM 절에 위치

FROM 절 내부에서 하나의 가상 테이블(Virtual Table) 역할을 담당하는 서브쿼리입니다. 실무에서 가장 활용도가 높은 서브쿼리 유형 중 하나이며, 다음 11화에서 독자적인 테마로 매우 심도 있게 다룰 예정입니다.

3. 현업 비즈니스 사례로 보는 중첩 서브쿼리의 실무 적용

서브쿼리가 실무 비즈니스 분석 과정에서 다단계 필터링 조건을 어떻게 세련되게 해결해 주는지, 실제 커머스 또는 금융권 마케팅 부서에서 자주 발생하는 가상의 시나리오를 바탕으로 코드를 빌드해 보겠습니다.

📊 [실무 사례 예시: 기획 팀 오 과장의 타겟 추출 업무]

온라인 백화점의 마케팅 기획 담당자인 오 과장은 이번 주말 VIP 타겟 프로모션을 앞두고 다음과 같은 조건의 대상자 추출 요청을 받았습니다.

  • 요청 내용: “최근 1주일 동안 발생한 구매 고객 중, 7월 전체 고객의 평균 1회 구매 금액을 초과하여 지출한 우수 고객들의 회원번호와 실제 구매 금액을 뽑아주세요.”

오 과장은 ‘7월 전체 평균 구매 금액’이라는 가변적인 기준값을 수동으로 계산해서 쿼리에 직접 적는 대신, 다음과 같이 WHERE 절 내부에 중첩 서브쿼리를 삽입하여 자동화된 조건절을 완성했습니다.

-- [올바른 예시] WHERE절 내에 중첩 서브쿼리를 적용하여 평균 초과 대상자를 추출한 쿼리
SELECT 
    A.CUST_NO
  , A.PURCHASE_AMT
FROM 
    DW_MART.WEEKLY_PURCHASE_LOG A       -- 메인 쿼리: 최근 1주일 구매 로그
WHERE 
    A.PURCHASE_AMT > (
        SELECT 
            AVG(SUB.PURCHASE_AMT) 
        FROM 
            DW_MART.MONTHLY_PURCHASE_LOG SUB -- 서브쿼리: 7월 전체 구매 로그
        WHERE 
            SUB.BASE_YYMM = '202607'
    );

💡 오 과장의 쿼리가 돌아가는 논리 구조 분석

  1. 시스템은 괄호 () 내부에 격리된 서브쿼리를 먼저 실행하여 ‘7월 전체 고객의 평균 1회 구매 금액’에 해당하는 단 하나의 숫자 값(예: 75,000원)을 계산해 냅니다.
  2. 서브쿼리가 반환한 단일 숫자는 메인 쿼리의 대소 비교 연산자(>) 우측에 자동으로 대입됩니다.
  3. 결과적으로 메인 쿼리는 WHERE A.PURCHASE_AMT > 75000이라는 간결한 필터 상태로 변환되어, 최근 1주일간 75,000원을 초과하여 지출한 대상자들만 정밀하게 추출해 낼 수 있게 됩니다.

4. 팩트 체크 및 데이터 분석가의 관점 점검

기술적 정확성을 지키기 위해, 실무에서 서브쿼리를 다룰 때 초보 분석가들이 가장 많이 범하는 오해와 실수들을 명확히 점검해 보겠습니다.

  • 서브쿼리는 무조건 조인(Join)보다 느리거나 비효율적인가?
    • 팩트 체크: 과거 구형 데이터베이스 환경이나 특정 복잡한 조건문 구조에서는 서브쿼리가 메인 쿼리의 매 행마다 반복 실행되어 성능 저하를 유발하는 경우가 존재하기도 했습니다. 그러나 대용량 처리를 지원하는 최신 데이터베이스나 테라데이터의 지능형 옵티마이저(Optimizer)는 사용자가 작성한 서브쿼리를 내부적으로 분석하여, 조인 형태로 쿼리를 자동 변환(Query Rewrite)하거나 최적의 실행 계획을 수립하는 능력이 뛰어난 것으로 알려져 있습니다. 따라서 “서브쿼리는 무조건 지양해야 한다”는 고정관념보다는, 데이터의 분산 상태와 인덱스 구조에 맞춰 쿼리를 짜고 실행 속도를 모니터링하는 것이 대안으로 권장됩니다.
  • WHERE 절 서브쿼리에서 다중 행 반환 시 등호(=)를 써도 되는가?
    • 팩트 체크: 절대 안 됩니다. 현업에서 가장 빈번하게 발생하는 쿼리 중단 에러 중 하나입니다. 예를 들어 WHERE CUST_NO = (SELECT CUST_NO FROM ...) 구조에서 서브쿼리가 반환하는 회원번호가 2건 이상인 경우, 시스템은 “Subquery returned more than one row” (서브쿼리가 두 개 이상의 행을 반환했습니다)라는 오류를 뿜으며 멈춰 섭니다. 등호(=)나 대소 비교 연산자는 오직 ‘단 하나의 값’과만 대조할 수 있는 단일 행 연산자이기 때문입니다. 서브쿼리의 결과가 여러 건으로 출력될 가능성이 조금이라도 존재한다면, 등호 대신 복수의 리스트를 수용할 수 있는 IN 구문을 배치해야 문법적 대참사를 막을 수 있습니다.

5. 서브쿼리 사용 시 실무 가독성 확보 전략

서브쿼리는 강력한 문법이지만, 하나의 코드 창에 서브쿼리가 서너 개 이상 중첩되어 꼬리를 물기 시작하면 쿼리의 가독성이 급격히 무너집니다. 내가 짠 코드를 한 달 뒤의 나나 팀원들이 쉽게 이해할 수 있도록 돕는 실무 가이드 표를 제공합니다.

서브쿼리 유형흔히 발생하는 가독성 저하 요인현직 분석가의 추천 대안 및 튜닝
SELECT 절 (스칼라)메인 쿼리 출력 행수가 많을 때 칼럼 단위 결합 복잡도 상승스칼라 서브쿼리를 반복 사용하는 대신 JOIN 구조로 전환하는 방안 검토
WHERE 절 (중첩)서브쿼리 내에 또 서브쿼리가 들어가 괄호 층위가 깊어짐들여쓰기(Indentation)를 명확히 하거나 임시 테이블 구조 활용
FROM 절 (인라인 뷰)가상 테이블의 크기가 너무 커져 전체 구조 파악 어려움명확한 별칭(Alias)을 부여하고 11화에 연재될 표준 인라인 뷰 규칙 적용

6. 결론 및 다음 화 예고

이번 10화에서는 쿼리 내부에 또 다른 조회를 삽입하여 다단계 비즈니스 로직을 단 한 문장으로 구현하는 서브쿼리의 위치별 종류와 문법적 규칙을 살펴보고, 실무 다중 행 처리 시 발생할 수 있는 에러 유형과 가독성 최적화 전략을 다각도로 점검해 보았습니다. 서브쿼리를 유연하게 다루는 역량은 복잡하게 꼬인 비즈니스 요구사항을 깔끔한 하나의 파이프라인으로 구조화하는 훌륭한 밑거름이 됩니다.

서브쿼리의 세 가지 종류 중, 분석가들이 복잡한 집계 연산과 대용량 테이블 마트를 결합할 때 가장 활용 빈도가 높은 형태는 단연 FROM 절에 위치하는 서브쿼리입니다.

이어지는 11화에서는 FROM 절 내부에서 독립적인 임시 테이블처럼 작동하며 복잡한 비즈니스 로직을 단계별로 깔끔하게 쪼개어 가독성을 극대화해 주는 인라인 뷰 (Inline View)를 집중적으로 파헤쳐 보겠습니다. 거대하게 꼬인 수백 줄짜리 스파게티 코드를 인라인 뷰를 활용해 책의 목차처럼 일목요연하게 리팩토링하는 현직자들의 핵심 모듈화 치트키를 비즈니스 사례와 실제 쿼리 비교 예시를 통해 상세히 파악해 보겠습니다.

댓글 남기기