세미 조인 튜닝 실습
세미 조인 튜닝
개발자를 위한 오라클 SQL 튜닝 내용에서 참고한 내용입니다.
Intro
세미 조인(Semi Join) 기법을 이용한 성능 극대화
CREATE TABLE TB_CUST
(
CUST_ID VARCHAR2(10), -- 고객ID
CUST_NM VARCHAR2(50) -- 고객명
);
CREATE TABLE TB_CUST_DTL
(
CUST_ID VARCHAR2(10), -- 고객ID
SEQ NUMBER(3), -- 시퀀스
CUST_INFO VARCHAR2(150) -- 고객정보
);
CREATE TABLE TB_ORD
(
ORD_NO VARCHAR2(10), -- 주문번호
ORD_DT VARCHAR2(8), -- 주문일자
CUST_ID VARCHAR2(10) -- 고객ID
);회원 정보 및 상세 정보 생성
주문 정보 생성
제약 조건 생성
인덱스 생성 및 통계 정보 갱신
튜닝 전 쿼리
SQL 분석
LEADING 힌트를 사용하여 TB_CUST 테이블을 가장 먼저 스캔 하여 테이블 풀스캔으로 유도
USE_NL 힌트를 이용하여 TB_CUST_DTL 테이블과 중첩 루프 조인 연산 후 TB_ORD 테이블과 중첩 루프 조인을 유도
SQL의 문제점
TB_ORD 테이블이 가지고 있는 컬럼은 SELECT 절에 존재하지 않는다.
TB_ORD 테이블은 EXISTS 유무만 판단해도 결과 집합에 영향을 주지 않는다.
즉, 해당 테이블은 세미 조인으로 튜닝할 수 있다.
Execute Plan
TB_CUST 테이블을 테이블 풀 스캔 한다.
TB_CUST_DTL_PK를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
6번에서 찾은 ROWID를 이용하여 TB_CUST_DTL 테이블을 테이블 랜덤 액세스(TABLE ACCESS BY INDEX ROWID)한다.
5번과 6번의 연산을 중첩 루프 조인(NESTED LOOPS)한다.
TB_ORD_IDX01 인덱스를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
4번과 8번의 연산을 중첩 루프 조인(NESTED LOOPS)한다.
3번과 나온 TB_ORD_IDX01의 ROWID 값으로 TB_ORD 테이블에 테이블 랜덤 액세스(TABLE ACCESS BY INDEX ROWID) 한다.
3번과 9번의 연산을 중첩 루프 조인(NESTED LOOPS)한다.
GROUP BY 연산을 수행한다.
SELECT 절의 연산을 수행한다.

튜닝
SQL 분석
LEADING 힌트를 이용하여 가장 작은 테이블인 TB_CUST 테이블을 Outer 테이블로 지정하고 FULL 힌트로 Outer 테이블을 테이블 풀 스캔한다.
USE_NL 힌트를 사용하여 TB_CUST_DTL을 Inner 테이블로 지정하고 중첩 루프 조인을 수행한다.
EXISTS문을 이용하여 TB_ORD 테이블의 존재 여부를 확인한다.
NL_SJ 힌트를 이용하여 중첩 루프 세미 조인으로 유도한다.
INDEX 힌트를 이용하여 TB_ORD_IDX01 인덱스를 사용하도록 한다.
Execute Plan
TB_CUST 테이블을 테이블 풀 스캔(Table access full)한다.
TB_CUST_DTL_PK 인덱스를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
5번에서 나온 ROWID를 이용하여 TB_CUST_DTL 테이블을 테이블 랜덤 액세스(TABLE ACCESS BY INDEX ROWID)한다.
3번과 4번의 연산을 중첩 루프 조인(NESTED LOOPS)한다.
TB_ORD_IDX01 인덱스를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
7번에서 나온 ROWID를 이용하여 TB_ORD 테이블을 테이블 랜덤 액세스(Table access by index ROWID)한다.
2번과 6번의 연산을 중첩 루프 세미 조인(Nested Loops Semi) 한다.
SELECT 절의 연산을 수행한다.

안티 세미 조인
EXISTS문을 NOT EXISTS로 바꾸면 안티 세미 조인이 성립된다.
SQL 분석
NOT EXISTS문을 이용하여 TB_CUST 테이블과 TB_CUST_DTL 테이블의 조인 결과 중 CUST_ID 컬럼을 기준으로 TB_ORD 테이블 내에 존재하지 않는 행을 검색
NL_AJ 힌트를 이용하여 중첩 루프 안티 세미 조인으로 유도한다.
INDEX 힌트를 이용하여 TB_ORD_IDX01 인덱스를 사용하도록 한다.
Execute Plan
TB_CUST 테이블을 테이블 풀 스캔(TABLE ACCESS FULL)한다.
TB_CUST_DTL_PK 인덱스를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
5번에서 나온 ROWID를 바탕으로 TB_CUST_DTL 테이블을 테이블 랜덤 액세스(TABLE ACCESS BY INDEX ROWID)한다.
3번과 4번의 연산을 중첩 루프 조인(NESTED LOOPS)한다.
TB_ORD_IDX01 인덱스를 인덱스 범위 스캔(INDEX RANGE SCAN)한다.
7번에서 나온 ROWID를 이용하여 TB_ORD 테이블을 테이블 랜덤 액세스(TABLE ACCESS BY INDEX ROWID) 한다.
2번과 6번의 연산을 중첩 루프 안티 세미 조인(NESTED LOOPS ANTI)한다.
SELECT 절의 연산을 수행한다.

Last updated
Was this helpful?