조인 연산의 핵심 결정 요소
복수 테이블을 결합하는 SQL 문이 실행될 때, 오라클 옵티마이저는 세 가지 핵심 사항을 결정해야 최종 실행 계획을 수립할 수 있다.
조인 순서(Join Order)
세 개 이상의 테이블이 참여하는 조인 연산에서, 오라클은 이진 트리 형태로 순차적으로 두 테이블씩 결합해 나간다. 이 과정에서 선행 테이블(Outer Table)과 후행 테이블(Inner Table)을 지정하며, 다중 테이블 환경에서는 어떤 테이블 쌍을 먼저 결합할지, 그 결과 집합을 어떤 테이블과 다음에 연결할지를 순차적으로 결정한다.
조인 방식(Join Method)
두 테이블 간 데이터 결합에는 다음 네 가지 알고리즘이 존재한다:
- Sort Merge Join: 양쪽 테이블을 정렬한 후 병합
- Nested Loops Join: 외부 테이블의 각 행에 대해 내부 테이블 반복 스캔
- Hash Join: 해시 테이블을 활용한 등가 조인
- Cartesian Join: 카티시안 곱(조인 조건 없는 결합)
단일 테이블 접근 방식(Access Path)
각 테이블의 데이터를 어떻게 추출할지 결정한다. 전체 테이블 스캔(Full Table Scan) 대신 인덱스를 활용할 경우, 인덱스 범위 스캔(Index Range Scan)이나 인덱스 고유 스캔(Index Unique Scan) 등의 세부 방법을 선택한다.
조인 유형 분류
SQL 문법의 작성 방식에 따라 조인 결과가 달라진다. 주요 유형은 내부 조인과 외부 조인으로 구분된다.
내부 조인(Inner Join)
조인 조건을 완전히 만족하는 행만 결과에 포함한다. WHERE 에 LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN 키워드나 오라클 고유의 (+) 연산자가 없으면 내불 조인으로 처리된다.
실습 환경 구성
-- 테이블 생성
CREATE TABLE dept_info (
dept_id NUMBER,
dept_code VARCHAR2(1)
);
CREATE TABLE emp_info (
emp_code VARCHAR2(1),
emp_name VARCHAR2(10)
);
-- 데이터 삽입
INSERT INTO dept_info VALUES (10, 'A');
INSERT INTO dept_info VALUES (20, 'B');
INSERT INTO dept_info VALUES (30, 'C');
INSERT INTO emp_info VALUES ('A', '홍길동');
INSERT INTO emp_info VALUES ('B', '김철수');
INSERT INTO emp_info VALUES ('D', '이영희');
COMMIT;
오라클 전용 구문
SELECT d.dept_id, d.dept_code, e.emp_name
FROM dept_info d, emp_info e
WHERE d.dept_code = e.emp_code;
DEPT_ID DEPT_CODE EMP_NAME
------- --------- ----------
10 A 홍길동
20 B 김수
ANSI 표준 구문
-- JOIN ... ON 형태
SELECT d.dept_id, d.dept_code, e.emp_name
FROM dept_info d
JOIN emp_info e ON (d.dept_code = e.emp_code);
-- JOIN ... USING 형태 (열 이름 동일 시)
SELECT dept_id, dept_code, emp_name
FROM dept_info
JOIN emp_info USING (dept_code);
주의: USING 절에서 조인 열을 SELECT 목록에 포함할 때는 테이블 별칭을 붙이면 ORA-25154 오류가 발생한다. dept_code로만 작성해야 한다.
NATURAL JOIN
양 테이블의 동일한 이름을 가진 모든 열을 자동으로 조인 조건으로 사용한다.
SELECT dept_id, dept_code, emp_name
FROM dept_info
NATURAL JOIN emp_info;
단, 의미적으로 다른 열이 이름만 같을 경우 잘못된 결과를 초래할 수 있어 권장하지 않는다.
외부 조인(Outer Join)
조인 조건을 만족하지 않는 행도 결과에 포함하며, 해당하는 열은 NULL 값으로 채워진다.
| 유형 | 구문 | 설명 |
|---|---|---|
| 좌측 외부 조인 | LEFT OUTER JOIN | 왼쪽 테이블의 모든 포함 |
| 우측 외부 조인 | RIGHT OUTER JOIN | 오른쪽 테이블의 모든 행 포함 |
| 전체 외부 조인 | FULL OUTER JOIN | 양쪽 테이블의 모든 행 포함 |
좌측 외부 조인 실습
SELECT d.dept_id, d.dept_code, e.emp_name
FROM dept_info d
LEFT OUTER JOIN emp_info e ON (d.dept_code = e.emp_code);
DEPT_ID DEPT_CODE EMP_NAME
------- --------- ----------
10 A 홍길동
20 B 김철수
30 C
dept_code='C'인 행은 emp_info에 매칭되는 값이 없어 emp_name이 NULL로 표시된다.
우측 외부 조인 실습
SELECT d.dept_id, d.dept_code, e.emp_name
FROM dept_info d
RIGHT OUTER JOIN emp_info e ON (d.dept_code = e.emp_code);
DEPT_ID DEPT_CODE EMP_NAME
------- --------- ----------
10 A 홍길동
20 B 김철수
이영희
emp_code='D'인 행은 dept_info에 매칭되는 값이 없어 왼쪽 열들이 NULL로 표시된다.
전체 외부 조인 실습
SELECT d.dept_id, d.dept_code, e.emp_name
FROM dept_info d
FULL OUTER JOIN emp_info e ON (d.dept_code = e.emp_code);
DEPT_ID DEPT_CODE EMP_NAME
------- --------- ----------
10 A 홍길동
20 B 김철수
30 C
이영희
양쪽 테이블의 매칭되지 않는 모든 행이 결과에 포함된다. 논리적으로는 좌측 외부 조인과 우측 외부 조인의 UNION 연산과 유사하나, 실제 실행 시에는 정렬 없이 단일 패스로 처리된다.
추가 필터 조건의 영향
조인 조건 외에 WHERE 절에 추가적인 제한 조건이 존재할 경우, 해당 조건의 위치와 조인 유형에 따라 결과 집합이 달라질 수 있다. 특히 외부 조인에서 필터 조건의 배치는 NULL 값 처리에 중대한 영향을 미친다.