SQLP
시험 직전 요약장
판단 기준과 헷갈리는 개념, 대표 예제를 짧게 확인하세요.
상관 서브쿼리 FILTER 실행: Starts·조기 종료·Semi/Anti Join
원래 이론 →판단 기준
| 혼동하기 쉬운 판단 | 정확한 기준 |
|---|---|
| 상관 서브쿼리는 항상 Outer 행 수만큼 완전히 실행된다 | 재사용·조기 종료·Transformation에 따라 실제 Starts와 작업량이 달라진다 |
실행계획의 FILTER는 모두 상관 서브쿼리다 | 일반 Predicate 평가에도 사용되므로 하위 Row Source와 Predicate를 함께 본다 |
| 동일 Key가 반복되면 Subquery는 정확히 NDV만큼 실행된다 | Cache 충돌과 Plan 구조가 있으므로 실제 Starts로 확인한다 |
| 한 번의 Index Probe가 싸면 FILTER 전체도 싸다 | 작은 비용도 수십만 번 반복되면 큰 총량이 된다 |
EXISTS 안의 SELECT 값이 NULL이면 FALSE다 | SELECT 값이 아니라 조건을 만족하는 행의 존재를 검사한다 |
| Semi Join은 FILTER보다 항상 빠르다 | Outer 크기, Index Probe 비용, 첫 행·전체 처리 목표에 따라 달라진다 |
| Starts는 Cache Miss 횟수다 | Row Source 시작 횟수이며 Cache Hit Counter가 아니다 |
| FILTER 비용에 Outer Row 수와 Starts를 모두 곱한다 | Starts에 실제 반복 횟수가 이미 반영된다 |
| Inner Match가 10건이면 Semi Join도 Outer를 10건 반환한다 | 존재 판정이므로 Outer Row는 한 번만 반환 |
| NULL 상관 Key끼리는 Equality로 Match한다 | NULL = NULL은 UNKNOWN이므로 명시적 Null-safe 조건 필요 |
| Unnesting Hint가 있으면 항상 Join으로 변환된다 | 의미적·구조적 제한과 Hint 적용 여부를 확인 |
| A-Rows가 0이면 Inner Probe 비용도 0이다 | 반환 Row가 없어도 Index·Table Block을 읽을 수 있다 |
헷갈리는 개념
같은 존재 Query가 Unnesting되면 Semi Join 후보가 될 수 있습니다.
FILTER 방식
Outer Row마다 Subquery Probe
SEMI JOIN 방식
두 입력을 하나의 Join Graph에서 최적화
| 조건 | FILTER가 유리할 수 있는 상황 | Semi Join이 유리할 수 있는 상황 |
|---|---|---|
| Outer 크기 | 매우 작음 | 큼 |
| Inner Access | 단건 Index Probe | 대량 Scan·Hash 처리 |
| 첫 행 응답 | 빠를 수 있음 | Build가 필요하면 늦을 수 있음 |
| 전체 처리 | 반복 횟수가 적을 때 | 반복 Probe를 집합 처리로 줄일 때 |
| Join Order | Outer 중심으로 제한될 수 있음 | Subquery 쪽을 먼저 읽는 후보 가능 |
두 방식은 결과 의미가 같아도 비용 구조가 다릅니다.
Semi Join은 Inner에 Match Row가 여러 개 있어도 Outer Row를 한 번만 반환합니다.
Outer 주문 1건
Inner Item Match 10건
→ SEMI JOIN 결과 Outer 주문 1건
일반 Inner Join은 별도 DISTINCT가 없으면 Outer Row가 Match 수만큼 증식할 수 있으므로 EXISTS를 단순 Join으로 수동 변경할 때 결과 Cardinality를 검증합니다.
Anti Join도 Match가 하나라도 발견되면 Outer Row를 제거하고 Inner 중복 수만큼 결과를 늘리지 않습니다.
NO_UNNEST와 기본 Plan을 제한적으로 비교해 FILTER 비용을 관찰할 수 있지만, Hint는 결과 의미를 정의하지 않으며 최종 판단은 Hint 없는 정상 Plan과 실제 업무 조건을 기준으로 합니다.
대표 계산·예제
FILTER 방식의 기본 비용은 다음처럼 생각할 수 있습니다.
전체 비용
≈ Outer Row Source 생성 비용
+ 실제 Subquery 반복 작업량
실제 Subquery 반복 작업량
≈ Subquery Starts × Starts당 Inner 평균 작업량
Outer Row 수를 다시 곱하지 않습니다. Starts 자체가 실제 반복 시작 횟수를 이미 나타냅니다.
예를 들어 실행 통계가 다음과 같습니다.
ORDERS TABLE ACCESS A-Rows = 1,000,000
CUSTOMER Subquery Root Starts = 950,000
CUSTOMER Index Scan Buffers = 2,850,000
Subquery가 거의 Outer 행 수만큼 시작됐고, Index Scan에서 약 285만 Buffer를 사용했습니다.
1회 평균 Buffer
≈ 2,850,000 ÷ 950,000
≈ 3 Blocks
한 번의 Probe가 3 Buffer로 작아 보여도 95만 번 반복되면 전체 부하는 큽니다.
A-Rows와 Buffers는 Plan Row Source에서 누적값으로 표시될 수 있으므로 다음 평균을 함께 계산합니다.
Starts당 Inner 반환 Row
= Inner A-Rows ÷ Subquery Starts
Starts당 Inner Buffer
= Inner Buffers ÷ Subquery Starts
다만 A-Rows=0이어도 Index Block을 여러 개 읽을 수 있으므로 반환 Row 수만으로 Probe 비용을 판단하지 않습니다.
반대로 Outer 1,000행, Subquery Starts 20, Inner Buffers 60이라면 반복 Key 재사용이나 다른 최적화로 실제 Subquery 작업량이 매우 작을 수 있습니다.
내 최근 연습 오답
현재 브라우저의 연습 채점 기록에서 공개된 단원과 연결된 오답을 확인합니다.
오답 기록을 확인하고 있습니다.