39. 일반 집합 연산자

핵심 인사이트 (3줄 요약)

  1. 본질: 두 개의 릴레이션(테이블)을 대상으로 수학적 집합 이론의 원리(합성, 공통 분모, 차이, 교차 생성)를 적용하여 새로운 릴레이션을 파생시키는 관계 대수 연산입니다.
  2. 가치: 서로 다른 데이터 소스에서 동일한 형태의 데이터를 결합하거나 배제할 때 사용되며, 집합적 사고를 통해 다중 쿼리 결과를 우아하게 제어할 수 있습니다.
  3. 융합: 합/교/차집합은 반드시 차수와 도메인이 일치해야 하는 '합립성(Union Compatibility)' 조건이 필수적이며, 카티션 프로덕트는 무조건 결합하여 향후 조인(Join) 연산의 토대가 됩니다.

Ⅰ. 개요 및 필요성 (Context & Necessity)

데이터베이스의 본질은 무결성을 유지하며 데이터를 관리하는 거대한 '집합(Set)' 저장소라는 점입니다. 여러 테이블이나 여러 번의 검색 조건에서 파생된 결과들을 하나로 묶어 비교하거나, 공통된 것만 걸러내거나, 특정 집단을 덜어내야 하는 업무 요구사항은 매일같이 발생합니다.

이러한 요구를 해결하기 위해 관계 대수는 수학에서 오랫동안 검증된 집합론(Set Theory)의 개념을 릴레이션 조작에 그대로 차용했습니다. 일반 집합 연산자(Set Operators)인 합집합(Union), 교집합(Intersection), 차집합(Difference), 카티션 프로덕트(Cartesian Product)는 단일 테이블 내의 조작을 넘어, 이기종 테이블 간의 데이터를 병합하고 대조하는 가장 직관적이고 근본적인 연산 도구입니다.

아래는 단일 쿼리로 해결할 수 없는 비즈니스 로직이 집합 연산자를 통해 통합되는 구조적 배경을 보여줍니다.

[비즈니스 요구사항과 집합 연산의 연결]

요구: "서울 지사의 우수 직원과 부산 지사의 우수 직원을 하나의 보고서로 뽑아라"

[ 기존 한계 구조 (애플리케이션 병합) ]
[서울 지사 쿼리] ──> 메모리 로드 ──┐
                                  ├──> 앱에서 중복 체크 및 병합 (속도 저하, 메모리 폭발)
[부산 지사 쿼리] ──> 메모리 로드 ──┘

[ 집합 연산자 적용 아키텍처 (DB 계층 처리) ]
[서울 지사 쿼리] ──( ∪ UNION 합집합 )──> [최종 병합 릴레이션 1개 즉시 반환]
[부산 지사 쿼리] ──/                     (DB 엔진의 고속 정렬 및 중복 제거 최적화)

이 도식은 데이터의 병합 및 대조 책임을 애플리케이션 계층에서 데이터베이스 계층으로 밀어 넣었을 때의 이점을 보여줍니다. 데이터베이스 엔진은 내부적으로 소트(Sort) 공간과 해시 맵을 활용하여 중복 제거나 교집합 연산을 애플리케이션보다 수십 배 빠르게 처리합니다. 실무에서 여러 파티션이나 이력 테이블을 조회할 때 일반 집합 연산자는 필수 불가결한 무기가 됩니다.

📢 섹션 요약 비유: 마치 두 개의 서로 다른 동호회 명부가 있을 때, 두 명부를 하나로 합치거나(합집합), 두 곳 모두 가입한 사람만 찾거나(교집합), 한쪽에만 가입한 사람을 가려내는(차집합) 명부 정리 작업과 완전히 동일합니다.


Ⅱ. 아키텍처 및 핵심 원리 (Deep Dive)

일반 집합 연산 중 합집합, 교집합, 차집합을 수행하기 위해서는 두 릴레이션이 **합립 가능(Union Compatible)**해야 합니다. 합립성 조건: ① 두 릴레이션의 차수(Degree, 속성의 개수)가 같아야 하고, ② 대응하는 속성끼리 도메인(Data Type)이 호환되어야 합니다. 카티션 프로덕트는 이 조건이 필요 없이 무조건 조합합니다.

연산자기호SQL 연산메커니즘 및 특징
합집합 (Union)UNION두 릴레이션의 모든 튜플 반환. 수학적 집합이므로 중복 튜플은 1개만 남기고 자동 제거됨.
교집합 (Intersection)INTERSECT두 릴레이션에 동시에 존재하는 튜플만 추출.
차집합 (Difference)MINUS/EXCEPT기준 릴레이션(R)에는 있지만 대상(S)에는 없는 튜플을 반환. 연산의 교환 법칙이 성립하지 않음 (R-S ≠ S-R).
카티션 프로덕트 (Cartesian Product)×CROSS JOIN두 릴레이션의 모든 가능한 튜플 조합을 생성. 차수는 합해지고, 카디널리티(행)는 곱해짐.

아래는 합립성 조건을 만족하는 두 릴레이션에 대해 차집합과 합집합이 내부적으로 처리되는 메커니즘을 나타낸 상태 흐름도입니다.

[집합 연산 내부 처리 메커니즘 (UNION 및 MINUS)]

릴레이션 A (1, 2, 3) / 릴레이션 B (2, 3, 4)

1. [정렬(Sort) 또는 해시(Hash) 단계]
   - A 스캔 -> Sort/Hash Area 적재
   - B 스캔 -> Sort/Hash Area 적재

2. [비교 및 추출 단계]
   [UNION 연산의 경우]
   A의 1 -> B와 중복 안됨 -> 결과 포함
   A의 2 -> B에 존재함 -> 하나만 결과 포함 (중복 제거 비용 발생)
   => 결과: (1, 2, 3, 4)

   [MINUS 연산의 경우 (A - B)]
   A의 1 -> B에 없음 -> 결과 포함!
   A의 2 -> B에 존재 -> 버림 (필터링)
   => 결과: (1)

이 흐름의 핵심은 데이터베이스 엔진이 집합 연산을 수행하기 위해 보이지 않는 '정렬(Sort)'이나 '해시 맵 구성' 오버헤드를 반드시 치러야 한다는 점입니다. 단순한 검색(Select)과 달리 집합 간의 중복을 배제하거나 대조해야 하므로, 메모리 내에서 두 집단을 모두 펴놓고 비교하는 무거운 작업이 일어납니다. 반면, 카티션 프로덕트는 비교 없이 A의 모든 행에 B의 모든 행을 단순히 이어 붙이는 방식(M x N개 생성)이므로 카디널리티 폭발(Cardinality Explosion)을 야기합니다.

📢 섹션 요약 비유: 두 개의 블록 더미를 섞을 때, 똑같이 생긴 블록은 하나만 남기고 버리는 작업(합집합), 똑같은 것만 골라내는 작업(교집합), 한쪽에서 겹치는 블록을 쏙 빼버리는 작업(차집합)을 의미합니다. 카티션 프로덕트는 무조건 두 박스의 모든 짝을 다 맞춰서 거대한 탑을 쌓는 것입니다.


Ⅲ. 융합 비교 및 다각도 분석 (Comparison & Synergy)

현업의 쿼리 튜닝에서 가장 많이 대립하는 구도는 "집합 연산자를 사용할 것인가, 아니면 논리적 조인/서브쿼리로 회피할 것인가"입니다. 집합 연산자는 직관적이지만 성능 트레이드오프가 존재합니다.

구분쿼리 방식장점단점 및 병목 지점
UNION (합집합)집합 연산 기반직관적인 데이터 결합, 쿼리 가독성 우수전체 결과를 대상으로 한 중복 제거용 'Sort Unique' 부하 발생
UNION ALL집합 연산 (비표준/실무)중복 제거 생략으로 압도적 속도, 부하 최소화결과에 중복 데이터 포함, 사용자가 필터링 감당
MINUS vs NOT EXISTS차집합 vs 서브쿼리차집합(MINUS)이 더 선언적상황에 따라 서브쿼리(NOT EXISTS)가 해시 조인을 타면서 성능 압도
CROSS JOIN카티션 프로덕트더미 데이터, 시계열 골격 생성에 유용행 수 곱셈으로 인한 심각한 I/O 및 메모리 마비 위험

아래는 실무에서 가장 큰 성능 차이를 유발하는 UNIONUNION ALL의 내부 처리 방식 차이를 보여주는 비교 매트릭스 흐름도입니다.

[UNION과 UNION ALL의 내부 파이프라인 차이]

[방식 A: UNION (정통 합집합)]
결과 세트 A ──┐
              ├──> [ SORT (정렬) ] ──> [ UNIQUE (중복 제거) ] ──> 최종 반환 (느림)
결과 세트 B ──┘    (Temp Tablespace 사용 가능성 큼)

[방식 B: UNION ALL (실무 권장 병합)]
결과 세트 A ──┐
              ├──> (추가 연산 없이 단순히 아래로 이어 붙임) ──> 최종 반환 (매우 빠름)
결과 세트 B ──┘    (스트리밍 파이프라인 유지)

이 비교의 핵심은 정렬(Sort)의 유무입니다. 수학적 합집합인 UNION은 중복 튜플을 허용하지 않으므로, 데이터베이스는 무조건 100만 건, 200만 건의 데이터를 정렬한 뒤 중복을 솎아내야 합니다. 이는 CPU 자원을 극심하게 소모합니다. 반면, 실무에서 설계된 테이블들은 이미 PK가 분리되어 있어 중복이 발생하지 않는다는 사실을 개발자가 미리 알고 있다면, 수학적 합집합 대신 UNION ALL을 사용하여 정렬 비용(Sort Cost)을 완전히 날려버릴 수 있습니다. 이는 성능 튜닝의 기본 철칙입니다.

📢 섹션 요약 비유: UNION은 모인 사람들의 얼굴을 일일이 확인해서 쌍둥이는 한 명만 입장시키는 깐깐한 경호원이고, UNION ALL은 줄 서 있는 사람들을 검사 없이 그대로 뒷줄로 연결해주는 고속 패스와 같습니다.


Ⅳ. 실무 적용 및 기술사적 판단 (Strategy & Decision)

일반 집합 연산자는 강력하지만 시스템 부하를 유발하는 주범이 되기도 합니다. 기술사는 성능적 관점과 데이터 무결성 관점에서 정확한 도입 잣대를 가져야 합니다.

실무 의사결정 및 적용 시나리오:

  1. 대량 테이블 분할 조회 (파티셔닝 회피): 물리적 파티셔닝(Partitioning)이 불가능한 레거시 환경에서, 연도별로 생성된 SALES_2023, SALES_2024 테이블을 UNION ALL로 묶어 가상 뷰(View)를 생성하여 애플리케이션의 쿼리를 단순화합니다.
  2. 카티션 프로덕트를 활용한 데이터 복제 (Dummy Table): 분석 보고서를 만들 때, 데이터가 없는 날짜에도 '0'으로 행을 띄워야 하는 경우(Dense Report). 달력 데이터를 가진 차원 테이블과 기준 테이블을 CROSS JOIN (카티션 프로덕트) 하여 빈 껍데기 시계열 뼈대를 억지로 생성하는 고급 기법을 사용합니다.
  3. 교집합(INTERSECT)과 차집합(MINUS)의 조인 변환: 실무에서는 MINUS 연산자가 대량의 데이터 정렬을 유발하여 타임아웃이 발생할 수 있습니다. 이를 안티 조인(Anti-Join, LEFT OUTER JOIN ... WHERE ... IS NULL)이나 NOT EXISTS 서브쿼리로 변환하면, 옵티마이저가 해시 맵을 활용하여 정렬 없이 초고속으로 차집합 결과를 도출해 냅니다.

아래는 카티션 프로덕트의 위험성과 이를 조인으로 제어하는 의사결정 트리입니다.

[카티션 프로덕트 발생 경고 및 방어 로직]

SELECT * FROM 주문(1만 건), 고객(1만 건)
   │
   ├──> 조인 조건(WHERE 주문.고객ID = 고객.ID) 누락? 
   │      │
   │      ├── [YES] ──> ⚠️ 카티션 프로덕트 (1만 * 1만 = 1억 건 반환!) 
   │      │              -> Temp 영역 고갈, DB 세션 락, 서비스 마비 장애 발생
   │      │
   │      └── [NO]  ──> ✅ 동등 조인으로 최적화 (1만 건 반환) -> 정상 처리
   │
   └──> 의도적 더미 복제인가? ──> [YES] ──> CROSS JOIN 명시적 사용으로 리뷰어에게 알림

이 의사결정 트리의 핵심은 '실수'에 의한 카티션 프로덕트가 실무에서 가장 무서운 안티패턴이라는 점입니다. 1만 건 테이블 두 개를 조인 조건 없이 실수로 결합하면 1억 건의 데이터 폭발이 일어나 서버의 메모리가 즉각적으로 고갈(OOM)될 수 있습니다. 항상 조인 키를 명확히 명시하거나(조인), 명시적으로 CROSS JOIN 구문을 써서 의도된 곱셈임을 증명해야 합니다.

📢 섹션 요약 비유: 일반 집합 연산은 강력한 포크레인 같습니다. 잘 쓰면 거대한 흙더미(데이터)를 순식간에 합치고 깎아내지만, 조작을 잘못해서 카티션 프로덕트 스위치를 누르면 흙더미가 수만 배로 복제되어 공사장을 파괴해버릴 수 있습니다.


Ⅴ. 기대효과 및 결론 (Future & Standard)

일반 집합 연산자는 데이터를 테이블이라는 고립된 섬에 가두지 않고, 전사적 데이터 통합을 이루는 가교 역할을 합니다. 집합 연산을 올바르게 제어함으로써 얻는 효과는 막대합니다.

도입 전 (절차적/애플리케이션 의존)도입 후 (관계 대수 집합 연산 활용)실무적 기대효과
수십 개의 루프(Loop)를 도는 복잡한 코드UNION / MINUS 구문 단 몇 줄로 해결쿼리 가독성 10배 향상 및 코드 양 감소
애플리케이션 서버의 메모리 OOM 위험DB 서버의 강력한 Sort/Hash 엔진 활용안정적인 대용량 집합 대조 및 추출 보장
파편화된 다중 데이터 소스 조회하나로 통합된 뷰(View) 형태로 제공데이터 추상화 및 외부 스키마(External Schema) 캡슐화

미래 전망: 클라우드 기반의 분산 데이터 웨어하우스(Snowflake, BigQuery) 시대가 열리면서, 데이터의 크기는 테라바이트(TB)를 넘어 페타바이트(PB) 수준에 이르렀습니다. 이러한 환경에서는 페타바이트 단위의 합집합, 차집합을 정렬 기반으로 처리하는 것이 물리적으로 불가능합니다. 따라서 최신 엔진들은 집합 연산을 수행할 때 블룸 필터(Bloom Filter), 해시 파티셔닝 재분배, 분산 맵리듀스(MapReduce) 등 고도의 물리적 최적화 기술을 이 집합 연산자 뒤에 투명하게 숨겨 제공하는 방향으로 진화하고 있습니다.

📢 섹션 요약 비유: 일반 집합 연산자는 데이터를 다루는 '마법의 덧셈, 뺄셈' 기호입니다. 이 기호 하나가 1억 명의 가입자 명단에서 탈퇴자 명단을 단 1초 만에 깔끔하게 도려내는 강력한 연산의 원천입니다.


📌 관련 개념 맵 (Knowledge Graph)

  • 합립성 (Union Compatibility) | 집합 연산을 수행하기 위해 두 릴레이션의 속성 수와 데이터 타입이 완전히 일치해야 하는 필수 전제 조건
  • 카티션 프로덕트 (Cartesian Product) | 조건 없이 두 테이블의 모든 행을 곱하여 결합하는 무거운 연산으로, 성능 장애의 주범이 되기도 함
  • 옵티마이저 (Optimizer) | 차집합(MINUS) 등의 무거운 집합 연산을 서브쿼리 조인(Anti Join)으로 변환하여 속도를 높이는 DB 뇌
  • Sort Unique | UNION, INTERSECT 연산 시 릴레이션 내부의 중복된 튜플을 골라내기 위해 DB 엔진이 수행하는 고비용 정렬 작업
  • 안티 조인 (Anti-Join) | 차집합과 동일한 결과를 내면서도 정렬 비용 없이 해시 맵으로 특정 집단을 제외하는 실무 최적화 기법

👶 어린이를 위한 3줄 비유 설명

  1. 축구부 친구들 명단(A)과 야구부 친구들 명단(B)이 있어요.
  2. 합집합(UNION)은 이 두 명단을 합쳐서 '운동하는 모든 친구' 명단을 만드는 거예요. (물론 둘 다 하는 친구는 한 번만 적어요!)
  3. 교집합(INTERSECT)은 '축구도 하고 야구도 하는' 진짜 체력왕 친구들만 쏙 뽑아내는 마법의 방법이랍니다!