[SQLํŠœ๋‹]2023.11.23

๋ง๊ตฌ์”จยท2023๋…„ 11์›” 23์ผ

๐Ÿ“– ์†Œ๋ชฉ์ฐจ
1. nested loop ์กฐ์ธ
2. hash ์กฐ์ธ
3. sort merge ์กฐ์ธ
4. ์กฐ์ธ ์ˆœ์„œ์˜ ์ค‘์š”์„ฑ
5. outer ์กฐ์ธ
6. ์Šค์นผ๋ผ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ์ด์šฉํ•œ ์กฐ์ธ ํŠœ๋‹
7. ์กฐ์ธ์„ ๋‚ดํฌํ•œ DML ๋ฌธ ํŠœ๋‹
8. ๊ณ ๊ธ‰ ์กฐ์ธ ํ…Œํฌ๋‹‰

โœ๏ธ ๊ณ ๊ธ‰ ์กฐ์ธ ๋ฌธ์žฅ ํ…Œํฌ๋‹‰(SQLP์ค€๋น„๋ฅผ ์œ„ํ•œ ์„ฑ๋Šฅ ๊ณ ๋„ํ™”์ฑ…p.301)

โœ… ํŠœ๋‹์ผ€์ด์Šค 1. ๋ˆ„์  ๋ฐ์ดํ„ฐ ๊ตฌํ•˜๊ธฐ

โœ”๏ธ ํŠœ๋‹ ์ „

select /*+ gather_plan_statistics*/ ename, sal, 
                                   (select sum(sal)
                                      from emp e2
                                      where e2.empno <= e1.empno) sumsal
    from emp e1
    order by empno;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     14 |00:00:00.01 |     105 |       |       |          |
|   1 |  SORT AGGREGATE    |      |     14 |      1 |     14 |00:00:00.01 |      98 |       |       |          |
|*  2 |   TABLE ACCESS FULL| EMP  |     14 |      1 |    105 |00:00:00.01 |      98 |       |       |          |
|   3 |  SORT ORDER BY     |      |      1 |     14 |     14 |00:00:00.01 |     105 |  2048 |  2048 | 2048  (0)|
|   4 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
----------------------------------------------------------------------------------------------------------------

โœ”๏ธ ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics*/ 
        ename, sal, sum(sal) over(order by empno) sumsal
    from emp;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |     14 |00:00:00.01 |       7 |       |       |          |
|   1 |  WINDOW SORT       |      |      1 |     14 |     14 |00:00:00.01 |       7 |  2048 |  2048 | 2048  (0)|
|   2 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
----------------------------------------------------------------------------------------------------------------

โœ… ํŠœ๋‹์ผ€์ด์Šค 2. ๋ถ€์„œ๋ฒˆํ˜ธ๋ณ„๋กœ ๊ฐ๊ฐ ๋ˆ„์  ๋ฐ์ดํ„ฐ ๊ตฌํ•˜๊ธฐ

โœ”๏ธ ํŠœ๋‹ ์ „ (๋ฒ„ํผ ๊ฐฏ์ˆ˜ 105๊ฐœ)

select /*+ gather_plan_statistics*/ deptno, ename, sal,
        (select sum(sal)
          from emp e2
          where e2.empno <= e1.empno
          and e2.deptno=e1.deptno)sumsal
   from emp e1
   order by deptno, emptno;


โžก๏ธ ๊ฐ™์€ ๋ถ€์„œ๋ฒˆํ˜ธ๋ผ๋ฆฌ ๋ˆ„์ ๋œ ๊ฐ’์ด ๋‚˜์˜ค๊ณ ์žˆ๋‹ค.
โœ”๏ธ ํŠœ๋‹ ํ›„ (๋ฒ„ํผ ๊ฐฏ์ˆ˜ 7๊ฐœ)

select /*+ gather_plan_statistics*/ 
        deptno, ename, sal, sum(sal) over(partition by deptno order by empno) sumsal
    from emp; 

โœ… ํŠœ๋‹์ผ€์ด์Šค 3. ์ด ํ•ฉ ๊ตฌํ•˜๊ธฐ

โœ”๏ธ ํŠœ๋‹ ์ „

select /*+ gather_plan_statistics*/  decode(no,1, deptno, 2, null)  as deptno, sum(sal)
               from  emp  e,  (select  rownum  no
                                  from  dual
                                  connect  by level <= 2 )  d
               group  by  decode(no, 1, deptno, 2, null )
               order by deptno;


โœ”๏ธ ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics*/  deptno, sum(sal)
  from emp
  group by rollup(deptno);

โœ… ํŠœ๋‹์ผ€์ด์Šค 4. ์ด ํ•ฉ ๊ตฌํ•˜๊ธฐ

โœ”๏ธ ํŠœ๋‹ ์ „

 select decode(no,1, to_char(deptno), 2, 'ํ† ํƒˆ')  as deptno, sum(sal)
               from  emp  e,  (select  rownum  no
                                  from  dual
                                  connect  by level <= 2 )  d
               group  by  decode(no, 1, to_char(deptno), 2, 'ํ† ํƒˆ' )
               order by deptno;

โœ”๏ธ ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics*/ nvl(to_char(deptno),'total'), deptno, sum(sal)
  from emp
  group by rollup(deptno);

โœ๏ธ ์ƒํ˜ธ ๋ฐฐํƒ€์  ๊ด€๊ณ„์˜ ์กฐ์ธ (์„ฑ๋Šฅ ๊ณ ๋„ํ™” 2๊ถŒ p.310)

โœ๐Ÿป ํ™˜๊ฒฝ๊ตฌ์„ฑ

@demo

alter  table  emp
    add  emp_kind   varchar2(1)  default  1  not  null;

update  emp
   set  emp_kind =  case  when  mod(empno,2) = 1  then  1
                            else  2  end ;

select  ename, emp_kind  from  emp;     
                                     -- emp_kind ๊ฐ€ 1์ด๋ฉด ์ •๊ทœ์ง 
                                     -- emp_kind ๊ฐ€ 2์ด๋ฉด ๋น„์ •๊ทœ์ง 

โœ”๏ธ ์ •๊ทœ์ง ์‚ฌ์› ํ…Œ์ด๋ธ” ์ƒ์„ฑ

 create  table  emp_kind1
   as
  select  empno, ename, sal + 200 as  office_sal
       from  emp
       where emp_kind ='1';

โœ”๏ธ ๋น„์ •๊ทœ์ง ์‚ฌ์› ํ…Œ์ด๋ธ” ์ƒ์„ฑ

 create  table  emp_kind2
   as
  select  empno, ename, sal + 200 as  sal
       from  emp
       where emp_kind ='2';

โœ”๏ธ primary key ์ œ์•ฝ์„ ๊ฐ๊ฐ ๊ฑด๋‹ค

 alter  table  emp_kind1
   add  constraint   pk_emp_kind1   primary  key(empno); 

 alter  table  emp_kind2
   add  constraint   pk_emp_kind2  primary  key(empno);

-- ์›”๊ธ‰ ์ปฌ๋Ÿผ ๋‚ ๋ฆฌ๊ธฐ
 alter  table  emp  
   drop  column  sal ;

 select  * from emp_kind1; 
 select  * from emp_kind2; 

โœ… ์•„๋ž˜์˜ SQL์„ ํŠœ๋‹ํ•˜๊ธฐ

-- emp_kind1(์ •๊ทœ์ง์‚ฌ์›) , emp_kind2(๋น„์ •๊ทœ์ง์‚ฌ์›), emp(๊ทธ๋ƒฅ์‚ฌ์›)
select /*+ gather_plan_statistics*/ e.empno, e.ename, k1.office_sal, k2.sal
  from emp e, emp_kind1 k1, emp_kind2 k2
  where e.empno = k1.empno(+)
  and e.empno = k2.empno(+)
  and e.empno = 7839;

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

------------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |              |      1 |        |      1 |00:00:00.01 |      10 |       |       |          |
|   1 |  MERGE JOIN OUTER              |              |      1 |      1 |      1 |00:00:00.01 |      10 |       |       |          |
|   2 |   MERGE JOIN OUTER             |              |      1 |      1 |      1 |00:00:00.01 |       9 |       |       |          |
|*  3 |    TABLE ACCESS FULL           | EMP          |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
|   4 |    BUFFER SORT                 |              |      1 |      1 |      1 |00:00:00.01 |       2 |  2048 |  2048 | 2048  (0)|
|   5 |     TABLE ACCESS BY INDEX ROWID| EMP_KIND1    |      1 |      1 |      1 |00:00:00.01 |       2 |       |       |          |
|*  6 |      INDEX UNIQUE SCAN         | PK_EMP_KIND1 |      1 |      1 |      1 |00:00:00.01 |       1 |       |       |          |
|   7 |   BUFFER SORT                  |              |      1 |      1 |      0 |00:00:00.01 |       1 |  1024 |  1024 |          |
|   8 |    TABLE ACCESS BY INDEX ROWID | EMP_KIND2    |      1 |      1 |      0 |00:00:00.01 |       1 |       |       |          |
|*  9 |     INDEX UNIQUE SCAN          | PK_EMP_KIND2 |      1 |      1 |      0 |00:00:00.01 |       1 |       |       |          |
------------------------------------------------------------------------------------------------------------------------------------

โžก๏ธ ํ•œ๋ช…์˜ ์‚ฌ์›์„ ์กฐํšŒํ•˜๋ ค๊ณ  ํ•˜๋Š”๋ฐ ์ •๊ทœ์ง์ธ์ง€ ๋น„์ •๊ทœ์ง์ธ์ง€ ๋ชจ๋ฅด๊ธฐ๋•Œ๋ฌธ์— 3๊ฐœ์˜ ํ…Œ์ด๋ธ”์„ ์กฐ์ธํ•  ์ˆ˜ ๋ฐ–์— ์—†๋Š” ์ƒํ™ฉ์ด๋‹ค. outer join sign์„ ์“ด ์ด์œ ๋Š” null๊ฐ’์ด ๋‚˜์˜ค๋Š” ๊ฒƒ์„ ๋ณด๋ ค๊ณ !
โžก๏ธ ์ •๊ทœ์ง ์‚ฌ์› ๋ฒˆํ˜ธ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ๋น„์ •๊ทœ์ง ์‚ฌ์›์ด๋ž‘ ์กฐ์ธ์„ ํ•˜๋ฉด ์•ˆ๋˜๊ณ , ๋น„์ •๊ทœ์ง ์‚ฌ์›์˜ ์‚ฌ์›๋ฒˆํ˜ธ๊ฐ€ ๋“ค์–ด์˜ค๋ฉด ์ •๊ทœ์ง ์‚ฌ์› ํ…Œ์ด๋ธ”์ด๋ž‘ ์กฐ์ธ์„ ํ•˜๋ฉด ์•ˆ๋˜๋Š”๋ฐ ์œ„ ์‹คํ–‰๊ณ„ํš๋ณด๋ฉด ๋‹ค ํ•˜๊ณ ์žˆ๋‹ค. ๋ฒ„ํผ๊ฐ€ 0์ด ์•„๋‹˜.

โœ”๏ธ ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics*/ e.empno, e.ename, k1.office_sal, k2.sal
  from emp e, emp_kind1 k1, emp_kind2 k2
  where decode(e.emp_kind,1, e.empno) = k1.empno(+)
  and (e.emp_kind,2, e.empno) = k2.empno(+)
  and e.empno = 7839;

(e.emp_kind,1, e.empno) 1์ด๋ฉด ์ •๊ทœ์ง์ผ๊ฑฐ๊ณ  2 ์ด๋ฉด ๋น„์ •๊ทœ์ง์ผ๊ฒƒ์ด๋‹ค. ์„ ํƒ์  ์กฐ์ธ์ด ๋˜๊ฒŒ๋” ํ•œ๋‹ค.

--------------------------------------------------------------------------------------------------------
| Id  | Operation                     | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT              |              |      1 |        |      1 |00:00:00.01 |       9 |
|   1 |  NESTED LOOPS OUTER           |              |      1 |      1 |      1 |00:00:00.01 |       9 |
|   2 |   NESTED LOOPS OUTER          |              |      1 |      1 |      1 |00:00:00.01 |       9 |
|*  3 |    TABLE ACCESS FULL          | EMP          |      1 |      1 |      1 |00:00:00.01 |       7 |
|   4 |    TABLE ACCESS BY INDEX ROWID| EMP_KIND1    |      1 |      1 |      1 |00:00:00.01 |       2 |
|*  5 |     INDEX UNIQUE SCAN         | PK_EMP_KIND1 |      1 |      1 |      1 |00:00:00.01 |       1 |
|   6 |   TABLE ACCESS BY INDEX ROWID | EMP_KIND2    |      1 |      1 |      0 |00:00:00.01 |       0 |
|*  7 |    INDEX UNIQUE SCAN          | PK_EMP_KIND2 |      1 |      1 |      0 |00:00:00.01 |       0 |
--------------------------------------------------------------------------------------------------------

โžก๏ธ ๋ฒ„ํผ์˜ ๊ฐฏ์ˆ˜๊ฐ€ 0์œผ๋กœ ๋ฐ”๋€Œ์—ˆ๋‹ค.


โœ๏ธ ์„œ๋ธŒ์ฟผ๋ฆฌ ํŠœ๋‹ ๋ฐฉ๋ฒ•

1. ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์‹คํ–‰๋˜๋Š” SQL (no_unnest)

1) ์„œ๋ธŒ์ฟผ๋ฆฌ ๋ถ€ํ„ฐ ์ˆ˜ํ–‰๋˜๋„๋ก ํ•  ์ˆ˜ ์žˆ์Œ (push_subq)
2) ๋ฉ”์ธ์ฟผ๋ฆฌ ๋ถ€ํ„ฐ ์ˆ˜ํ–‰๋˜๋กœ๋ก ํ•  ์ˆ˜ ์žˆ์Œ (no_push_subq)

2. ์ฟผ๋ฆฌ ๋ณ€ํ˜•๊ธฐ์— ์˜ํ•ด ์กฐ์ธ์œผ๋กœ ๋ณ€๊ฒฝ๋˜๋Š” SQL (unnest)

1) nested loop semi join (nl_sj)
2) hash semi join (hash_sj)
3) sort merge semi join (merge_sj)

4) nested loop anti join (nl_aj)
5) hash anti join (hash_aj)
6) sort merge anti join (merge_aj)

๋ฌธ์ œ1. ์•„๋ž˜ SQL์˜ ์‹คํ–‰๊ณ„ํ™•์€ ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ์ˆ˜ํ–‰๋˜๋Š”๊ฐ€ ์•„๋‹ˆ๋ฉด ์กฐ์ธ์œผ๋กœ ๋ณ€๊ฒฝ์ด ๋˜์–ด ์ˆ˜ํ–‰๋˜๋Š”๊ฐ€??

select /*+ gather_plan_statistics*/ ename, sal 
 from emp
 where deptno in (select deptno 
                   from dept
                   where deptno=10);

SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST'));

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      3 |00:00:00.01 |      10 |       |       |          |
|*  1 |  HASH JOIN SEMI    |      |      1 |      3 |      3 |00:00:00.01 |      10 |  1557K|  1557K|  400K (0)|
|*  2 |   TABLE ACCESS FULL| EMP  |      1 |      3 |      3 |00:00:00.01 |       7 |       |       |          |
|*  3 |   TABLE ACCESS FULL| DEPT |      1 |      1 |      1 |00:00:00.01 |       3 |       |       |          |
----------------------------------------------------------------------------------------------------------------

-- ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics*/ ename, sal 
 from emp
 where deptno in (select /*+ no_unnest */ deptno 
                   from dept
                   where deptno=10);


no_unnest ๋ถ€์ •์ด ๋‘๊ฐœ๋ผ ๊ฐ•ํ•œ ๊ธ์ •. ์‹ฌํ•˜๊ฒŒ ๊ฐ์‹ธ๋ผ ! -> ์ฆ‰ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ฅผ ํ•ด์ฒดํ•ด์„œ ์กฐ์ธ์„ ํ’€์ง€ ๋ง๊ณ  ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ํ’€์–ด๋ผ!
โžก๏ธ ๋ฉ”์ธ ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰์ด ๋˜์—ˆ๋‹ค.

๋ฌธ์ œ2. ์œ„ SQL์€ ๋ฉ”์ธ ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰์ด ๋˜์—ˆ๋Š”๋ฐ, ์„œ๋ธŒ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰๋˜๊ฒŒ ํ•ด๋ณด๊ธฐ

select /*+ gather_plan_statistics*/ ename, sal 
 from emp
 where deptno in (select /*+ no_unnest push_subq */ deptno 
                   from dept
                   where deptno=10);

โžก๏ธ select /*+ no_unnest push_subq */ : ์„œ๋ธŒ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰ํ•ด๋ผ
โžก๏ธ select /*+ no_unnest no_push_subq */ : ๋ฉ”์ธ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰ํ•ด๋ผ

๋ฌธ์ œ3. ์•„๋ž˜์˜ SQL์ด ์ˆœ์ˆ˜ํ•˜๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ์‹คํ–‰๋˜๊ฒŒ ํ•˜๋Š”๋ฐ ์„œ๋ธŒ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰๋˜๊ฒŒ ํ•˜๊ธฐ

-- ํŠœ๋‹ ์ „
select ename, sal
  from emp
  where sal = (select max(sal)
                from emp );

-- ํŠœ๋‹ ํ›„
select /*+ gather_plan_statistics QB_NAME(main) */ ename, sal
from emp
where sal = (select /*+ no_unnest push_subq QB_NAME(sub) */ max(sal) from emp);
                
select * from table(dbms_xplan.display_cursor(format=>'advanced'));  

----------------------------------------------------------------------------
| Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     |
----------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |       |       |     6 (100)|          |
|*  1 |  TABLE ACCESS FULL  | EMP  |     1 |    20 |     3   (0)| 00:00:01 |
|   2 |   SORT AGGREGATE    |      |     1 |    13 |            |          |
|   3 |    TABLE ACCESS FULL| EMP  |    14 |   182 |     3   (0)| 00:00:01 |
----------------------------------------------------------------------------
 
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
 
   1 - MAIN / EMP@MAIN
   2 - SUB 
   3 - SUB  / EMP@SUB

โžก๏ธ QB_NAME ํžŒํŠธ๋Š” ์ฟผ๋ฆฌ์˜ ์ด๋ฆ„์„ ์ง€์ •ํ•ด์ฃผ๋Š” ํžŒํŠธ์ด๋‹ค. ๊ด„ํ˜ธ ์•ˆ์—๋Š” ๋งˆ์Œ๋Œ€๋กœ ์จ๋„ ๋จ!
์ˆœ์ˆ˜ํ•˜๊ฒŒ ์„œ๋ธŒ์ฟผ๋ฆฌ๋กœ ์ˆ˜ํ–‰๋˜๋Š”๊ฒŒ ๋А๋ฆฌ๋‹ค๋ฉด ์กฐ์ธ์œผ๋กœ ๋ณ€๊ฒฝํ•˜๋Š”๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค!!!

๋ฌธ์ œ4. ์•„๋ž˜์˜ SQL์„ ์กฐ์ธ์œผ๋กœ ์ˆ˜ํ–‰๋˜๊ฒŒ๋” ํžŒํŠธ๋ฅผ ์ฃผ๊ธฐ!

select ename, sal
  from emp
  where deptno in (select deptno
                    from emp
                    where loc = 'DALLAS');

  SELECT * 
FROM TABLE(dbms_xplan.display_cursor(null,null,'ALLSTATS LAST')); 

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      5 |00:00:00.01 |      14 |       |       |          |
|*  1 |  HASH JOIN SEMI    |      |      1 |      5 |      5 |00:00:00.01 |      14 |  1557K|  1557K|  625K (0)|
|   2 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
|*  3 |   TABLE ACCESS FULL| DEPT |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
----------------------------------------------------------------------------------------------------------------
select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno in (select/*+ unnest nl_sj */ deptno
                    from dept
                    where loc = 'DALLAS');

-------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      5 |00:00:00.01 |      24 |
|   1 |  NESTED LOOPS SEMI |      |      1 |      5 |      5 |00:00:00.01 |      24 |
|   2 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |
|*  3 |   TABLE ACCESS FULL| DEPT |      3 |      1 |      1 |00:00:00.01 |      17 |
-------------------------------------------------------------------------------------

โžก๏ธ SEMI JOIN์„ํ–ˆ๋‹ค. SEMI์˜ ๋œป์ด ์ ˆ๋ฐ˜ ์ด๋ผ๋Š” ๋œป์ด์žˆ๋‹ค. ์™„์ „ํ•œ ์กฐ์ธ์€ ์กฐ์ธ ์ˆœ์„œ์™€ ์กฐ์ธ ๋ฐฉ๋ฒ•์„ ์ž์œ ๋กญ๊ฒŒ ํžŒํŠธ๋ฅผ ํ†ตํ•ด ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ semi ์กฐ์ธ์€ ์กฐ์ธ ๋ฐฉ๋ฒ•์€ ์ž์œ ๋กญ๊ฒŒ ํžŒํŠธ๋ฅผ ํ†ตํ•ด ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š”๋ฐ ์กฐ์ธ ์ˆœ์„œ๋ฅผ ๋ชป๋ฐ”๊พผ๋‹ค. ๋ฌด์กฐ๊ฑด ๋ฉ”์ธ์ฟผ๋ฆฌ๋ถ€ํ„ฐ ์ˆ˜ํ–‰๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ ˆ๋ฐ˜์˜ ์กฐ์ธ์ด๋‹ค. ํ•ด์‰ฌ ์„ธ๋ฏธ ์กฐ์ธ๋งŒ ์กฐ์ธ ์ˆœ์„œ๋ฅผ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

๋ฌธ์ œ5. ์•„๋ž˜์˜ SQL์„ ํ•ด์‰ฌ ์„ธ๋ฏธ ์กฐ์ธ์œผ๋กœ ์ˆ˜ํ–‰๋˜๊ฒŒ ํ•˜๊ธฐ

select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno in (select/*+ unnest nl_sj */ deptno
                    from dept
                    where loc = 'DALLAS');
select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno in (select/*+ unnest hash_sj */ deptno
                    from dept
                    where loc = 'DALLAS');

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      5 |00:00:00.01 |      14 |       |       |          |
|*  1 |  HASH JOIN SEMI    |      |      1 |      5 |      5 |00:00:00.01 |      14 |  1557K|  1557K|  647K (0)|
|   2 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
|*  3 |   TABLE ACCESS FULL| DEPT |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
----------------------------------------------------------------------------------------------------------------

โžก๏ธ ์ง€๊ธˆ hash table์ด emp ์ด๋‹ค. ๊ทผ๋ฐ dept๊ฐ€ ์˜ฌ๋ผ๊ฐ€์•ผํ•จ

๋ฌธ์ œ6. ์œ„ SQL์˜ ํ•ด์‰ฌ ํ…Œ์ด๋ธ”์ด dept๊ฐ€ ๋˜๊ฒŒ ํ•˜๊ธฐ

select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno in (select/*+ unnest hash_sj swap_join_inputs(dept) */ deptno
                    from dept
                    where loc = 'DALLAS');

------------------------------------------------------------------------------------------------------------------
| Id  | Operation            | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |      |      1 |        |      5 |00:00:00.01 |      14 |       |       |          |
|*  1 |  HASH JOIN RIGHT SEMI|      |      1 |      5 |      5 |00:00:00.01 |      14 |  2440K|  2440K|  712K (0)|
|*  2 |   TABLE ACCESS FULL  | DEPT |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
|   3 |   TABLE ACCESS FULL  | EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
------------------------------------------------------------------------------------------------------------------

โžก๏ธ ํžŒํŠธ๋Š” ์„œ๋ธŒ์ฟผ๋ฆฌ์ชฝ์— ์ฃผ๊ธฐ

๋ฌธ์ œ7. ์•„๋ž˜ SQL์„ ํŠœ๋‹ํ•˜๊ธฐ

select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno not in (select deptno
                        from dept
                        where loc='DALLAS');

----------------------------------------------------------------------------------------------------------------
| Id  | Operation          | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT   |      |      1 |        |      9 |00:00:00.01 |      14 |       |       |          |
|*  1 |  HASH JOIN ANTI NA |      |      1 |     14 |      9 |00:00:00.01 |      14 |  1557K|  1557K|  649K (0)|
|   2 |   TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
|*  3 |   TABLE ACCESS FULL| DEPT |      1 |      1 |      1 |00:00:00.01 |       7 |       |       |          |
----------------------------------------------------------------------------------------------------------------

โžก๏ธ ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์กฐ์ธ์œผ๋กœ ํ’€๋ฆด ๋•Œ not in์„ ์‚ฌ์šฉํ–ˆ์œผ๋ฉด anti join์ด ๋œ๋‹ค. ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ์กฐ์ธ์œผ๋กœ ํ’€๋ฆด ๋•Œ in์„ ์‚ฌ์šฉํ–ˆ์œผ๋ฉด semi join์ด ๋‚˜์˜จ๋‹ค.
์œ„ ์‹คํ–‰๊ณ„ํš์—์„œ ํ•ด์‰ฌ ํ…Œ์ด๋ธ”์ด dept๊ฐ€ ์•„๋‹ˆ๋ผ emp์—ฌ์„œ ํŠœ๋‹์ด ํ•„์š”ํ•œ ๊ฒƒ์ด๋‹ค.

โœ”๏ธ deptํ…Œ์ด๋ธ”์ด ํ•ด์‰ฌ ํ…Œ์ด๋ธ”์ด ๋˜๋„๋ก ํŠœ๋‹!!

select /*+ gather_plan_statistics */ ename, sal
  from emp
  where deptno not in (select /*+ unnest hash_aj swap_join_inputs(dept) */ deptno
                        from dept
                        where loc='DALLAS'
                        and deptno is not null)
   and deptno is not null;

โžก๏ธ not in์œผ๋กœ ์“ด ์„œ๋ธŒ์ฟผ๋ฆฌ๊ฐ€ ๊ต‰์žฅํžˆ ๋А๋ฆด ๋•Œ and deptno is not null์„ ๊ผญ ์ถ”๊ฐ€ํ•˜๊ธฐ.

๋ฌธ์ œ8. ์•„๋ž˜์˜ SQL์„ ํŠœ๋‹ํ•˜๊ธฐ

-- customers100 ๋งŒ๋“ค๊ธฐ
create table customers100 as select * from sh.customers;
create table sales100 as select * from sh.sales;

-- ํŠœ๋‹ ์ „
select /*+ gather_plan_statistics */ count(*) 
  from customers100 c
  where c.cust_id not in (select /*+ no_unnest push_subq */ cust_id
                             from sales100
                             where amount_sold between 0 and 10000);

โœ”๏ธ ํŠœ๋‹ ํ›„

select /*+ gather_plan_statistics */ count(*) 
  from customers100 c
  where c.cust_id not in (select /*+ unnest hash_aj */ cust_id
                             from sales100 
                             where amount_sold between 0 and 10000);

----------------------------------------------------------------------------------------------------------------------------------
| Id  | Operation           | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |  OMem |  1Mem | Used-Mem |
----------------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |              |      1 |        |      1 |00:00:00.40 |    5852 |   5845 |       |       |          |
|   1 |  SORT AGGREGATE     |              |      1 |      1 |      1 |00:00:00.40 |    5852 |   5845 |       |       |          |
|*  2 |   HASH JOIN ANTI NA |              |      1 |  48304 |  47799 |00:00:00.40 |    5852 |   5845 |  4010K|  3056K| 4596K (0)|
|   3 |    TABLE ACCESS FULL| CUSTOMERS100 |      1 |  48304 |  54288 |00:00:00.03 |    1416 |   1413 |       |       |          |
|*  4 |    TABLE ACCESS FULL| SALES100     |      1 |    712K|    918K|00:00:00.18 |    4436 |   4432 |       |       |          |
----------------------------------------------------------------------------------------------------------------------------------

โžก๏ธ swap_join_inputs ์•ˆ์จ์„œ where ๋ฐ‘์— ์กฐ๊ฑด ๋นผ์ฃผ์—ˆ๋‹ค.

๋ทฐ๋ฅผ ํ•ด์ฒดํ•˜๊ฑฐ๋‚˜ ํ•ด์ฒดํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ํžŒํŠธ

1. merge : view, in line view๋ฅผ ํ’€์–ดํ•ด์ณ๋ผ
2. no_merge : view, in line view๋ฅผ ํ’€์–ดํ•ด์น˜์ง€ ๋ง์•„๋ผ

select /*+ gather_plan_statistics */ v.ename, v.loc, s.grade
  from salgrade s, (select e.ename, d.loc, e.sal, e.deptno
                     from emp e, dept d
                     where e.deptno = d.deptno ) v
  where v.sal between s.losal and s.hisal;

โžก๏ธ ์‹คํ–‰๊ณ„ํš์—์„œ ๋ทฐ๊ฐ€ ์•ˆ๋‚˜์˜ค๋Š” ์ด์œ ๋Š” ์ฟผ๋ฆฌ ๋ณ€ํ˜•๊ธฐ๊ฐ€ in line view๋ฅผ ํ•ด์ฒดํ•ด์„œ ์ด๋‹ค. ์ฟผ๋ฆฌ ๋ณ€ํ˜•๊ธฐ๊ฐ€ ์•„๋ž˜์™€ ๊ฐ™์ด SQL์„ ๋ณ€๊ฒฝํ–ˆ๋‹ค. ๋ทฐ๋ฅผ ํ•ด์ฒดํ•˜์ง€ ๋ง๋ผ๊ณ  ํ•ด์•ผํ•œ๋‹ค !!! no_merge

select e.ename, d.loc, s.grade
  from emp e, dept d, salgrade s
  where e.deptno=d.deptno and e.sal between s.losal and s.hisal;
-- ํžŒํŠธ ์‚ฌ์šฉํ•˜๊ธฐ
select /*+ gather_plan_statistics no_merge(v) */ v.ename, v.loc, s.grade
  from salgrade s, (select e.ename, d.loc, e.sal, e.deptno
                     from emp e, dept d
                     where e.deptno = d.deptno ) v
  where v.sal between s.losal and s.hisal;

------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |      1 |        |     14 |00:00:00.01 |      20 |       |       |          |
|   1 |  MERGE JOIN            |          |      1 |      1 |     14 |00:00:00.01 |      20 |       |       |          |
|   2 |   SORT JOIN            |          |      1 |      5 |      5 |00:00:00.01 |       6 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL   | SALGRADE |      1 |      5 |      5 |00:00:00.01 |       6 |       |       |          |
|*  4 |   FILTER               |          |      5 |        |     14 |00:00:00.01 |      14 |       |       |          |
|*  5 |    SORT JOIN           |          |      5 |     14 |     40 |00:00:00.01 |      14 |  2048 |  2048 | 2048  (0)|
|   6 |     VIEW               |          |      1 |     14 |     14 |00:00:00.01 |      14 |       |       |          |
|*  7 |      HASH JOIN         |          |      1 |     14 |     14 |00:00:00.01 |      14 |  1696K|  1696K| 1071K (0)|
|   8 |       TABLE ACCESS FULL| DEPT     |      1 |      4 |      4 |00:00:00.01 |       7 |       |       |          |
|   9 |       TABLE ACCESS FULL| EMP      |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
------------------------------------------------------------------------------------------------------------------------

โœ”๏ธ ์ธ๋ผ์ธ๋ทฐ ๋ง๊ณ  ์ง„์งœ view๋งŒ๋“ค๊ธฐ

create or replace view emp142
as
select e.ename, d.loc, e.sal, e.deptno
                     from emp e, dept d
                     where e.deptno = d.deptno;

โœ”๏ธ view๋ž‘ ์กฐ์ธํ•˜๊ธฐ

select /*+ gather_plan_statistics */ v.ename, v.loc, s.grade
  from emp142 v, salgrade s
  where v.sal between s.losal and s.hisal;
>
-----------------------------------------------------------------------------------------------------------------------
| Id  | Operation             | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
-----------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |          |      1 |        |     14 |00:00:00.01 |      20 |       |       |          |
|*  1 |  HASH JOIN            |          |      1 |      1 |     14 |00:00:00.01 |      20 |  1557K|  1557K|  663K (0)|
|   2 |   MERGE JOIN          |          |      1 |      1 |     14 |00:00:00.01 |      13 |       |       |          |
|   3 |    SORT JOIN          |          |      1 |      5 |      5 |00:00:00.01 |       6 |  2048 |  2048 | 2048  (0)|
|   4 |     TABLE ACCESS FULL | SALGRADE |      1 |      5 |      5 |00:00:00.01 |       6 |       |       |          |
|*  5 |    FILTER             |          |      5 |        |     14 |00:00:00.01 |       7 |       |       |          |
|*  6 |     SORT JOIN         |          |      5 |     14 |     40 |00:00:00.01 |       7 |  2048 |  2048 | 2048  (0)|
|   7 |      TABLE ACCESS FULL| EMP      |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
|   8 |   TABLE ACCESS FULL   | DEPT     |      1 |      4 |      4 |00:00:00.01 |       7 |       |       |          |
-----------------------------------------------------------------------------------------------------------------------

โžก๏ธ ๋ทฐ๋ฅผ ํ•ด์ฒดํ–ˆ๋‹ค

โœ”๏ธ ๊ทธ๋ ‡๋‹ค๋ฉด view๋ฅผ ํ•ด์ฒดํ•˜์ง€ ์•Š๊ฒŒ ํ•˜๊ธฐ

select /*+ gather_plan_statistics no_merge(v) */ v.ename, v.loc, s.grade
  from emp142 v, salgrade s
  where v.sal between s.losal and s.hisal;

------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |      1 |        |     14 |00:00:00.01 |      20 |       |       |          |
|   1 |  MERGE JOIN            |          |      1 |      1 |     14 |00:00:00.01 |      20 |       |       |          |
|   2 |   SORT JOIN            |          |      1 |      5 |      5 |00:00:00.01 |       6 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL   | SALGRADE |      1 |      5 |      5 |00:00:00.01 |       6 |       |       |          |
|*  4 |   FILTER               |          |      5 |        |     14 |00:00:00.01 |      14 |       |       |          |
|*  5 |    SORT JOIN           |          |      5 |     14 |     40 |00:00:00.01 |      14 |  2048 |  2048 | 2048  (0)|
|   6 |     VIEW               | EMP142   |      1 |     14 |     14 |00:00:00.01 |      14 |       |       |          |
|*  7 |      HASH JOIN         |          |      1 |     14 |     14 |00:00:00.01 |      14 |  1696K|  1696K| 1071K (0)|
|   8 |       TABLE ACCESS FULL| DEPT     |      1 |      4 |      4 |00:00:00.01 |       7 |       |       |          |
|   9 |       TABLE ACCESS FULL| EMP      |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
------------------------------------------------------------------------------------------------------------------------

๋ฌธ์ œ2. ์œ„ ์‹คํ–‰๊ณ„ํš์— view ์•ˆ์˜ ํ…Œ์ด๋ธ”์˜ ์กฐ์ธ ์ˆœ์„œ๋ฅผ emp -> dept์ˆœ์ด ๋˜๊ฒŒ ํ•˜๊ธฐ

select /*+ gather_plan_statistics no_merge(v) leading(v.e v.d) */ v.ename, v.loc, s.grade
  from emp142 v, salgrade s
  where v.sal between s.losal and s.hisal;

------------------------------------------------------------------------------------------------------------------------
| Id  | Operation              | Name     | Starts | E-Rows | A-Rows |   A-Time   | Buffers |  OMem |  1Mem | Used-Mem |
------------------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT       |          |      1 |        |     14 |00:00:00.01 |      20 |       |       |          |
|   1 |  MERGE JOIN            |          |      1 |      1 |     14 |00:00:00.01 |      20 |       |       |          |
|   2 |   SORT JOIN            |          |      1 |      5 |      5 |00:00:00.01 |       6 |  2048 |  2048 | 2048  (0)|
|   3 |    TABLE ACCESS FULL   | SALGRADE |      1 |      5 |      5 |00:00:00.01 |       6 |       |       |          |
|*  4 |   FILTER               |          |      5 |        |     14 |00:00:00.01 |      14 |       |       |          |
|*  5 |    SORT JOIN           |          |      5 |     14 |     40 |00:00:00.01 |      14 |  2048 |  2048 | 2048  (0)|
|   6 |     VIEW               | EMP142   |      1 |     14 |     14 |00:00:00.01 |      14 |       |       |          |
|*  7 |      HASH JOIN         |          |      1 |     14 |     14 |00:00:00.01 |      14 |  1557K|  1557K|  662K (0)|
|   8 |       TABLE ACCESS FULL| EMP      |      1 |     14 |     14 |00:00:00.01 |       7 |       |       |          |
|   9 |       TABLE ACCESS FULL| DEPT     |      1 |      4 |      4 |00:00:00.01 |       7 |       |       |          |
------------------------------------------------------------------------------------------------------------------------

๋ฌธ์ œ3. (์ „์ฒด ๊ณผ์ •์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ œ) ์œ„ SQL์˜ ์‹คํ–‰ ๊ณ„ํš์ด ์•„๋ž˜์™€ ๊ฐ™์ด ์ถœ๋ ฅ๋˜๊ฒŒ ํ•˜๊ธฐ

select /*+ gather_plan_statistics no_merge(v) leading(v.e v.d) leading(v s) use_nl(s) */ v.ename, v.loc, s.grade
  from emp142 v, salgrade s
  where v.sal between s.losal and s.hisal;

profile
Slow and steady wins the race.

0๊ฐœ์˜ ๋Œ“๊ธ€