(개발시 SQL튜닝은 기본 입니다.)서브쿼리튜닝, 쿼리 변환(Query Transformation)에 대한 이해는 SQL튜닝의 핵심입니다. 서브쿼리 푸시 및 서브쿼리의 드라이빙을 제어할 수 있는 push_subq, no_push_subq 힌트에 대해 알아보고 실행방법에 따른 서브쿼리의 종류도 설명한 영상 입니다. SQL튜닝 교육은 탑크리에듀(www.topcredu.co.kr)에서 해결해 드리겠습니다.
3. Filter SubQuery
• 필터형 서브쿼리는 쿼리변형없이 서브쿼리가 메인쿼리의 값을 주입받아 서브쿼리에서
확인하는 방식이며 메인쿼리와 서브쿼리가 조인으로 풀리지 않고 Filter라는 연산으로
풀린다.
• 메인쿼리에 있는 테이블을 모두 액세스 후 각 레코드의 값을 하나씩 서브쿼리를 주입하
여 서브쿼리가 가장 나중에 실행되는 형태가 된다.
• 오라클 힌트중 서브쿼리를 조인으로 풀지말라는 힌트 no_unnest를 사용하면 Filter 연산
자가 주로 나타나며 서브쿼리의 조인칼럼에는 인덱스가 생성되어 있는것이 유리하다.
SELECT * FROM emp e
WHERE e.job = 'CLERK'
AND (SELECT loc
FROM dept d
WHERE d.deptno = e.deptno) = 'DALLAS';
4. Early Filter SubQuery
• 필터형 서브쿼리와 유사하게 쿼리변형없이 동작하지만 서브쿼리가 메인쪽으로 푸시되
면서 가능한 먼저 실행되어 데이터를 필터링하는 모습이며 오라클의 push_subq 힌트를
사용하면 Early Filter SubQuery 모양이 된다. (서브쿼리 푸싱을 방지하기 위해서는
no_push_subq 힌트를 사용한다)
• 확인자 서브쿼리(Filter형 SubQuery)에 push_subq 힌트를 사용하여 가능한 먼저 실행될
수 있도록 유도하는 서브쿼리를 Early Filter SubQuery라고 한다.
SELECT * FROM emp e
WHERE e.job = 'CLERK'
AND (SELECT /*+ push_subq */ loc
FROM dept d
WHERE d.deptno = e.deptno) = 'DALLAS';
5. Access SubQuery
• 서브쿼리는 값을 제공하는 제공자로서의 기능을 한다.
• 메인쿼리의 값이 서브쿼리로 주입되지 않는 형태이다.(메인쿼리의 값이 서브쿼리로 주
입되는 상관서브쿼리는 제공자가 될 수 없다.)
SELECT * FROM emp e
WHERE e.job = ‘CLERK’
AND deptno = (SELECT deptno FROM DEPT
WHERE loc = ‘DALLAS’)
6. Sub Query Pushing 이란?
• 오라클 옵티마이저는 서브쿼리 Unneting이 불가능 할 경우 서브쿼리를 메인쿼리로 이동
하여 드라이빙 순서를 제어하는 방법을 제공하는데 이것이 SubQuery Pushing이다.
• 서브쿼리의 처리 순서를 앞쪽에 푸시하겠가는 의미로 드라이빙을 제어하는 방법이다.
• 서브쿼리에 ROWNUM, DISTINCT, GROUP BY, SET 연산자(Union, Union All, Intersect, Minus)등이
있을 때 옵티마이저는 서브쿼리를 조인으로 푸는 Unnesting이 어려워져 서브쿼리 블록을 나중에
처리하는 실행계획을 세우는데 이때 서브쿼리의 앞쪽에 푸시하여 드라이빙 순서를 제어하는 방
법이다.
7. Sub Query Pushing Example1 - 1
-- 'DALLAS'에 위치한 부서에 근무하는 사원추출
-- VIEW MERGING이 발생하여 서브쿼리가 메인쿼리에 통합됨
SELECT * FROM emp e
WHERE e.job = 'CLERK'
AND (SELECT loc FROM dept d
WHERE d.deptno = e.deptno) = 'DALLAS';
1. EMP FULL SCAN해서 job='CLERK'
데이터4건 추출
2. DEPT테이블을 PK인덱스를
이용하여 엑세스(d.deptno = :b)
3. EMP에서 loc가 'DALLAS'인 데이터
필터링을 통해 추출, 이를 반복한다.
** FPD(Filter Push Down) 기능에
의해서 쿼리를 풀기위해
d.deptno=:b 조건을 서브쿼리에
밀어넣어서 실행계획을 생성한다.
좌측 서브쿼리는 확인자
서브쿼리인데 메인쿼리의 값을
제공받아 서브쿼리에서 체크하는
방식으로 Filter형 SubQuery이다.
8. Sub Query Pushing Example1 - 2
-- 'DALLAS'에 위치한 부서에 근무하는 사원추출
-- push_subq 힌트에 의해 서브쿼리가 메인쿼리에 푸시된다.
SELECT * FROM emp e
WHERE e.job = 'CLERK'
AND (SELECT /*+ push_subq */ loc FROM dept d
WHERE d.deptno = e.deptno) = 'DALLAS';
서브쿼리가 메인쿼리에
푸시되면서 FIler 연산이
사라지고 EMP에서 ‘job
이 ‘CLERK’이면서
서브쿼리의 조건까지
포함시켜 필터링하여
데이터 추출한다.
9. Sub Query Pushing 2 - 1
-- myemp1 : 1000만건, mydept1 : 8건, mylecture1 : 7건, mysugang1 : 550만건
-- myemp1테이블은 empno, deptno에 각각 인덱스가 생성되어 있다.
-- 스프링과목 수강내역이 있는 사원들의 이름, 부서명을 출력한다. 1.6초
SELECT e.empno, e.ename, d.dname FROM mydept1 d, myemp1 e
WHERE e.empno in (select empno from mysugang1 s, mylecture1 l
where s.lecture_id = l.lecture_id and l.lecture_nm like '%스프링%')
AND e.deptno = d.deptno;
서브쿼리를 독자적으로
실행한 후 그 결과와
myemp1을 해시조인 후
mydept1과 중첩루프조인
한다.
10. Sub Query Pushing ExampleSub Query Pushing Example2 - 2(push_subq)
-- 0초, 서브쿼리가 myemp1, mydept1과 같은 레벨에 푸시됨
SELECT e.empno, e.ename, d.dname
FROM mydept1 d, myemp1 e
WHERE e.empno in (select /*+ push_subq */ empno from mysugang1 s, mylecture1 l
where s.lecture_id = l.lecture_id and l.lecture_nm like '%스프링%')
AND e.deptno = d.deptno;
서브쿼리가 myemp1,
mydept1의 조인결과와 같은
레벨에서 필터링된다.
서브쿼리가
실행계획번호5~9번까지
서브쿼리를 실행하고 같은
레벨의 2~4번 실행계획에서
myemp1, mydept1을
deptno로 해시조인한 결과와
Filter를 수행한다.