본문 바로가기

sql_tuning

4. 서브쿼리 튜닝

728x90
반응형

서브쿼리 문장 튜닝

*서브쿼리 문장의 튜닝 방법 2가지

 

1. 순수하게 서브쿼리로 수행하면서 튜닝 :  no_unnest (힌트)

    -서브쿼리 부터 수행 : push_subq

    -메인쿼리 부터 수행 : no_push_subq

 *서브쿼리절에 힌트를 쓴다.

 

2. 서브쿼리를 조인으로 변경하면서 튜닝 : unnest

    -in   사용시

          1. nested loop semi 조인 : nl_sj

          2. hash semi 조인          : hash_sj

          3. merge semi 조인        : merge_sj

 

    -not in  사용시

          1. nested loop anti 조인 : nl_aj

          2. hash anti 조인          : hash_aj

          3. merge anti 조인        : merge_aj

        

 

 

 

 

 

문제68. SCOTT 같은 월급을 받는 사원의 이름,월급을 출력하시오

 

select ename, sal

from emp

where sal in (select sal

                        from emp

                        where ename = 'SCOTT')

 and ename ^=  'SCOTT';

 

 

오답:

 SELECT e.ename, ee.sal

 from ( select sal

         from emp

          where ename = 'SCOTT') ee, emp e;

 

 

 

 

 

select /*+ QB_NAME(main) */ ENAME, SAL

 FROM EMP

 WHERE SAL = (SELECT /*+ QB_NAME(sub) */ SAL

                            FROM EMP

                           WHERE ENAME = 'SCOTT');

 

실행계획-실제실행계획-ADVANCED ALLSTATS LAST

 

 

 

 

 

 

2 TABLE ACCESS FULL 제일 먼저 수행되었고,

 그것이 SUB . ( SUB 먼저 수행 )

 

※설명:

 QB_NAME(main) : 쿼리에 이름을 붙여주는 힌트

  QB_NAME(sub)   : 서브에 이름을 붙여주는 힌트

 

*실행계획의 종류 2가지?

 1. 예측 실행계획: SQL 실행해보기전에 미리 예측하는 .

 2. 실제 실행계획: SQL 실행하고 실행할 사용했던

                        실행계획.

 

 *QB_NAME 힌트에 대한 결과는 실제 실행계획에서만

   있다.

 

 

 

 

문제69. 위의 실행계획이 main query 부터 수행되게 하시오

 

select /*+ QB_NAME(main) */ ENAME, SAL

 FROM EMP

 WHERE SAL = (SELECT /*+ QB_NAME(sub)  no_push_subq */ SAL

                            FROM EMP

                           WHERE ENAME = 'SCOTT');

 

 

 

화면 캡처: 2018-11-12 오후 2:31

 

*no_push_subq 메인부터 수행하라는 힌트

(서브쿼리 절에 쓴다)

 

2 TABLE ACCESS FULL 부터 수행했고

 그것이 MAIN 임을 있다.

 

 

 

 

문제70. 아래의 SQL 서브쿼리부터 수행되게도 해보고

 메인쿼리부터 수행되게도 해보시오.

 

select count(*)

from sales

where time_id in(select time_id

                                from times100

                                where week_ending_day_id = 1581);

 

 

 

화면 캡처: 2018-11-12 오후 2:39

옵티마이져가 판단하에 성능 좋은걸로

자기마음대로 조인탔다.

 

 

 no_unnest  : 서브쿼리 하라.(서브쿼리로 강하게 감싸라)

        

select count(*)

from sales

where time_id in(select /*+ no_unnest */

                     time_id

                                from times100

                                where week_ending_day_id = 1581);

 

 

 

옵티마이져 마음대로 조인타던걸 unnest 막아버림.

 

 

 

1. 서브쿼리부터

select count(*)

from sales

where time_id in(select /*+ no_unnest  push_subq */

                                 time_id

                                from times100

                                where week_ending_day_id = 1581);

 

 

2. 메인쿼리부터

select count(*)

from sales

where time_id in(select /*+ no_unnest  no_push_subq */

                                 time_id

                                from times100

                                where week_ending_day_id = 1581);

 

 

no_unnest (no_)push_subq set. 함께 다닌다.

 

 

 

 

문제72. 아래의 sql 순수하게 서브쿼리로 수행되게 하고

서브쿼리부터 실행되게 하시오

select ename, sal, job

from emp

 where deptno in (select deptno

                                     from dept);

 

 

서브쿼리로, 서브쿼리부터 수행:

select ename, sal, job

from emp

 where deptno in (select /*+ unnest  push_subq */

                            deptno

                                     from dept);

 

 

 

문제73. 위의 sql 메인쿼리부터 수행되게 하시오.

 

서브쿼리로 감싸고, 메인쿼리부터 수행하라:

select ename, sal, job

from emp

 where deptno in (select /*+ unnest  no_push_subq */

                            deptno

                                     from dept);

 

 

 

***서브쿼리부터 수행하는게 빠르다. unnest  push_subq

 

 

**만약 no_unnest 안쓰면?

select ename, sal, job

from emp

 where deptno in (select /*+ push_subq */ deptno

                            from dept);

no_unnest 없이 쓰는 push_subq 의미없다.

옵티마이져가 hash join 타버림.

그래서 push_subq no_push_subq 힌트를 사용하려면

no_unnest 같이 사용해야 한다.

 

 

 

 

 

문제73. 안혜진 학생과 같은 전공인 학생들의

이름, 전공을 출력하시오

 

select ename, major

from emp2

where major in (select /*+ unnest push_subq */

                                      major

                              from emp2

                                where ename = '안혜진' );

 

IN 으로 연결해서

대용량 값이 나올거라 예상하는 옵티마이저가

HASH 돌려버렸다.

 

 

 

select ename, major

from emp2

where major = (select /*+ unnest push_subq */

                                      major

                              from emp2

                                where ename = '안혜진' );

 

= 연결해서

단일연산자가 나올거라 예상하는 옵티마이저가

HASH 없이 돌렸다.

 

 

 

문제74. 아래의 SQL 조인으로 풀리게 힌트를 주고

조인 방법 중에 NESTED LOOP 조인이 되게 하시오

 

select ename, major

from emp2

where major in (select /*+ unnest nl_sj */

                                      major

                              from emp2

                                where ename = '안혜진' );

 

 

 

 서브쿼리를 조인으로 변경하면서 튜닝 : unnest

           -in   사용시

          1. nested loop semi 조인 : nl_sj

          2. hash semi 조인          : hash_sj

          3. merge semi 조인        : merge_sj

 

 

서브쿼리로 수행되는 SQL 양쪽 대용량이면

 서브쿼리로 수행되는 보다는 조인으로 수행되는

  성능이 좋다.

 조인방법 중에 해쉬조인을 사용할 있기 때문이다.

select ename, major

from emp2

where major in (select /*+ unnest hash_sj */

                                      major

                              from emp2

                                where ename = '안혜진' );

 

 

 

※세미조인 (SEMI JOIN) ?  절반의 조인.

 완전한 조인이 아니라 절반의 조인인 이유는

 조인 방법은 3가지 중에 아무거나 사용할 있는데

 조인 순서는 고정이 된다.

 (메인쿼리 테이블--->서브쿼리 테이블로 고정 )

 

 

 

문제75. 위의 HASH 세미 조인의 조인순서를

 DEPT ----> EMP 변경하시오

 

select ename, sal, job

from emp

 where deptno in (select /*+ unnest  hash_sj

                                  swap_join_inputs(d) */

                            deptno

                                     from dept d);

 

 

문제76. 아래의 sql   hash join right semi 조인이

되게 하시오

 

튜닝전:

select count(*)

 from sales100

 where time_id in (select /*+ no_unnest

                                                     no_push_subq */

                                            time_id

                                    from times100

                                    where week_ending_day_id = 1581 );

 

튜닝후:

select count(*)

 from sales100

 where time_id in (select /*+ unnest

                                                     hash_sj

                                                 swap_join_inputs(t) */

                                            time_id

                                    from times100 t

                                    where week_ending_day_id = 1581 );

 

 

 

 

 

 

 

 

문제77. 아래와 같이 실행계획이 나오게 하시오

 

 

 

화면 캡처: 2018-11-12 오후 4:13

 

 select /*+ leading (s t) */ count(*)

    from SALES100 s

     where time_id in (select /*+ unnest  hash_sj */

                         time_id

                                    from times100 t

                                   where week_ending_day_id=1581);    

**왠만한 힌트는

서브쿼리 쪽인데, 안되면 메인쿼리에도 써보고 하는거다.

 

 

 

서브쿼리문 튜닝 방법 정리

 서브쿼리문의 데이터가 적을 때는 순수하게 서브쿼리로

수행되는게 좋은 성능을 보이나,

대용량 테이블 경우에는

해시세미조인으로 수행되게끔 힌트를 주면 유리하다.

  그리고 swap_join_inputs 힌트를 이용해서

  작은 테이블 부터 드라이빙 되게끔 조정할 있다.

 

 

 

 

728x90
반응형

'sql_tuning' 카테고리의 다른 글

6. 병렬처리  (0) 2019.04.02
5. 파티셔닝  (0) 2019.04.02
3. 조인 튜닝  (0) 2019.04.02
2-1. 인덱스 엑세스 방법  (0) 2019.04.02
2. 인덱스 튜닝  (0) 2019.04.02