DATABASE(oracleDB 11g)/Tuning

[SQL Tuning]옵티마이저 연산자

SEUNGSAMI 2019. 5. 3. 11:13
옵티마이저 연산자





Optimizer가 선택하는 Access PATH
  • Table Access
      • 전체 테이블 읽기(Full Table Scan : 실행 계획상에서는 'Table Access Full(TAF)' 로 출력) 
      • SQL> select * from emp;
      • SQL> select /*+ FULL(emp) */ * from emp where deptno=10;
          • HINT : Optimizer에게 이 경로를 이용하라고 지시
USER01@orcl2> select * from emp;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK           7902 17-DEC-80        800                    20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300         30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500         30
      7566 JONES      MANAGER         7839 02-APR-81       2975                    20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400         30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500          0         30
      7876 ADAMS      CLERK           7788 23-MAY-87       1100                    20
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

14 rows selected.
Elapsed: 00:00:00.01


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  a2dk8bdn0ujx7, child number 0
-------------------------------------
select * from emp

Plan hash value: 3956160932

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |     14 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS FULL| EMP  |      1 |     14 |     14 |00:00:00.01 |       4 |
------------------------------------------------------------------------------------

13 rows selected.

Elapsed: 00:00:00.04




USER01@orcl2> select /*+ FULL(emp) */ * from emp where deptno=10;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7782 CLARK      MANAGER         7839 09-JUN-81       2450                    10
      7839 KING       PRESIDENT            17-NOV-81       5000                    10
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

Elapsed: 00:00:00.01


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  2faurs97x9jr1, child number 0
-------------------------------------
select /*+ FULL(emp) */ * from emp where deptno=10

Plan hash value: 3956160932

------------------------------------------------------------------------------------
| Id  | Operation         | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |      |      1 |        |      3 |00:00:00.01 |       4 |
|*  1 |  TABLE ACCESS FULL| EMP  |      1 |      5 |      3 |00:00:00.01 |       4 |
------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("DEPTNO"=10)
Elapsed: 00:00:00.01

  • TABLE ACCESS BY ROWID
      • SQL> elect /*+ INDEX(EMP {INDEXNAME}) */ * from emp where empno=7788;
      • SQL> select /*+ INDEX(EMP(EMPNO)) */ * from emp where empno=7788;
          • emp table의 empno에 걸려있는 index를 써라.
USER01@orcl2> select /*+ INDEX(EMP(EMPNO)) */ * from emp where empno=7788;

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7788 SCOTT      ANALYST         7566 19-APR-87       3000                    20

Elapsed: 00:00:00.00


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  6qy4j9fsdpz1y, child number 0
-------------------------------------
select /*+ INDEX(EMP(EMPNO)) */ * from emp where empno=7788

Plan hash value: 247672086

----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name         | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |              |      1 |        |      1 |00:00:00.01 |       2 |      1 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMP          |      1 |      1 |      1 |00:00:00.01 |       2 |      1 |
|*  2 |   INDEX UNIQUE SCAN         | EMP_EMPNO_IX |      1 |      1 |      1 |00:00:00.01 |       1 |      1 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("EMPNO"=7788)
Elapsed: 00:00:00.01
-- index를 통해서 얻은 rowid값을 가지고 table access를 진행한다 => RANDOM ACCESS

  • TABLE ACCESS SAMPLE
      • SQL> select * from emp sample(10);
          • 데이터를 10%만 보고싶다는 의미이다.
USER01@orcl2> select * from emp sample(10);

     EMPNO ENAME      JOB              MGR HIREDATE         SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850                    30
      7900 JAMES      CLERK           7698 03-DEC-81        950                    30
      7902 FORD       ANALYST         7566 03-DEC-81       3000                    20
      7934 MILLER     CLERK           7782 23-JAN-82       1300                    10

Elapsed: 00:00:00.00


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
----------------------------------------------------------------------------------------------------
SQL_ID  46fsy9v9xk3wa, child number 0
-------------------------------------
select * from emp sample(10)

Plan hash value: 4089107469

--------------------------------------------------------------------------------------
| Id  | Operation           | Name | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |      |      1 |        |      4 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS SAMPLE| EMP  |      1 |      1 |      4 |00:00:00.01 |       4 |
--------------------------------------------------------------------------------------

Elapsed: 00:00:00.01



USER01@orcl2> select * from sales sample block(10);
........
84980 rows selected.
Elapsed: 00:00:00.96


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  9y2gwppt1m2k3, child number 0
-------------------------------------
select * from sales sample block(10)

Plan hash value: 3469240937

------------------------------------------------------------------------------------------------
| Id  | Operation           | Name  | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT    |       |      1 |        |  84980 |00:00:00.14 |    1262 |   1272 |
|   1 |  TABLE ACCESS SAMPLE| SALES |      1 |  91884 |  84980 |00:00:00.14 |    1262 |   1272 |
------------------------------------------------------------------------------------------------
Elapsed: 00:00:00.03



INDEX ACCESS

  • INDEX UNIQUE SCAN
      • UNIQUE INDEX=
      • SQL>select /*+ INDEX(e (employee_id))*/ * from employees e where department_id = 100 
USER01@orcl2> select /*+ INDEX(e (employee_id))*/ * from employees e where department_id = 100;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL                     PHONE_NUMBER         HIRE_DATE JOB_ID      SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- --------- ---------- ---------- -------------- ---------- -------------
        108 Nancy                Greenberg                 NGREENBE                  515.124.4569         17-AUG-02 FI_MGR       12008                        101           100
        109 Daniel               Faviet                    DFAVIET                   515.124.4169         16-AUG-02 FI_ACCOUNT     9000                       108           100
        110 John                 Chen                      JCHEN                     515.124.4269         28-SEP-05 FI_ACCOUNT     8200                       108           100
        111 Ismael               Sciarra                   ISCIARRA                  515.124.4369         30-SEP-05 FI_ACCOUNT     7700                       108           100
        112 Jose Manuel          Urman                     JMURMAN                   515.124.4469         07-MAR-06 FI_ACCOUNT     7800                       108           100
        113 Luis                 Popp                      LPOPP                     515.124.4567         07-DEC-07 FI_ACCOUNT     6900                       108           100

6 rows selected.



USER01@orcl2> @xplan
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  a20fjmnmwkdmw, child number 0
-------------------------------------
select /*+ INDEX(e (employee_id))*/ * from employees e where
department_id = 100

Plan hash value: 3013043712

----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |      1 |        |      6 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES      |      1 |     10 |      6 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN          | EMPL_DEPTNO_IX |      1 |     10 |      6 |00:00:00.01 |       2 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("DEPARTMENT_ID"=100)


  • INDEX RANGE SCAN
      • UNIQUE INDEX +  범위 조건 '>'
      • SQL> select /*+ INDEX(e (employee_id))*/ * from employees e where department_id > 100 
      • 가장 일반적인 접근방법, 기본적으로 ASCENDING으로 접근
USER01@orcl2> select /*+ INDEX(e (employee_id))*/ * from employees e where department_id > 100 ;

EMPLOYEE_ID FIRST_NAME           LAST_NAME                 EMAIL                     PHONE_NUMBER         HIRE_DATE JOB_ID      SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- --------- ---------- ---------- -------------- ---------- -------------
        205 Shelley              Higgins                   SHIGGINS                  515.123.8080         07-JUN-02 AC_MGR       12008                        101           110
        206 William              Gietz                     WGIETZ                    515.123.8181         07-JUN-02 AC_ACCOUNT     8300                       205           110

Elapsed: 00:00:00.00


USER01@orcl2> @xplan
PLAN_TABLE_OUTPUT
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  4jzm62x5skay1, child number 0
-------------------------------------
select /*+ INDEX(e (employee_id))*/ * from employees e where
department_id > 100

Plan hash value: 3013043712

----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |      1 |        |      2 |00:00:00.01 |       4 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES      |      1 |     11 |      2 |00:00:00.01 |       4 |
|*  2 |   INDEX RANGE SCAN          | EMPL_DEPTNO_IX |      1 |     11 |      2 |00:00:00.01 |       2 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("DEPARTMENT_ID">100)

      • NONUNIQUE  INDEX, =, 범위조건 '>'
USER01@orcl2> select * from employees where department_id = 10;


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  1cfy9v4kzrhq0, child number 0
-------------------------------------
select * from employees where department_id = 10

Plan hash value: 3013043712

----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name           | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |                |      1 |        |      1 |00:00:00.01 |       3 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES      |      1 |     10 |      1 |00:00:00.01 |       3 |
|*  2 |   INDEX RANGE SCAN          | EMPL_DEPTNO_IX |      1 |     10 |      1 |00:00:00.01 |       2 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - access("DEPARTMENT_ID"=10)

Elapsed: 00:00:00.02

  • INDEX FULL SCAN
      • 모든 LEAF BLOCLK을 순서대로 읽어낸다.
      • 사용되는 컬럼에 NOT NULL 제약조건 또는 조건식(IS NOT NULL)이 있을때
      • SINGLE BLOCK IO
USER01@orcl2> select count(*) from employees where employee_id is NOT NULL;

  COUNT(*)
----------
       107
Elapsed: 00:00:00.00


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  8vncmrfxz6tc9, child number 0
-------------------------------------
select count(*) from employees where employee_id is NOT NULL

Plan hash value: 3798089054

--------------------------------------------------------------------------------------------
| Id  | Operation        | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |               |      1 |        |      1 |00:00:00.01 |       1 |
|   1 |  SORT AGGREGATE  |               |      1 |      1 |      1 |00:00:00.01 |       1 |
|*  2 |   INDEX FULL SCAN| EMPL_EMPID_IX |      1 |    107 |    107 |00:00:00.01 |       1 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("EMPLOYEE_ID" IS NOT NULL)

Elapsed: 00:00:00.01
-- table access는 하지 않는다 왜냐하면 leaf block의 갯수만 세어도 무관하기 때문


USER01@orcl2> select employee_id from employees where employee_id IS NOT NULL;
......
107 rows selected.
Elapsed: 00:00:00.01


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  7632zyvp54wv8, child number 0
-------------------------------------
select employee_id from employees where employee_id IS NOT NULL

Plan hash value: 2656877640

--------------------------------------------------------------------------------------------
| Id  | Operation        | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
--------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT |               |      1 |        |    107 |00:00:00.01 |       3 |
|*  1 |  INDEX FULL SCAN | EMPL_EMPID_IX |      1 |    107 |    107 |00:00:00.01 |       3 |
--------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("EMPLOYEE_ID" IS NOT NULL)


USER01@orcl2> select employee_id, last_name from employees where employee_id IS NOT NULL;
......
107 rows selected.


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  3377j4y3250xs, child number 0
-------------------------------------
select employee_id, last_name from employees where employee_id IS NOT
NULL

Plan hash value: 1445457117

-----------------------------------------------------------------------------------------
| Id  | Operation         | Name      | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
-----------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT  |           |      1 |        |    107 |00:00:00.01 |       6 |
|*  1 |  TABLE ACCESS FULL| EMPLOYEES |      1 |    107 |    107 |00:00:00.01 |       6 |
-----------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   1 - filter("EMPLOYEE_ID" IS NOT NULL)




--/* INDEX (TABLE_NAME (COLUMN_NAME)) */
USER01@orcl2> SELECT /*+ INDEX (E (EMPLOYEE_ID)) */ EMPLOYEE_ID, LAST_NAME
                            FROM EMPLOYEES E
                            WHERE EMPLOYEE_ID IS NOT NULL;
......
107 rows selected.



USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  cxasajrftfzk4, child number 0
-------------------------------------
SELECT /*+ INDEX (E (EMPLOYEE_ID)) */ EMPLOYEE_ID, LAST_NAME FROM
EMPLOYEES E WHERE EMPLOYEE_ID IS NOT NULL

Plan hash value: 1119809800

----------------------------------------------------------------------------------------------------
| Id  | Operation                   | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |               |      1 |        |    107 |00:00:00.01 |       8 |
|   1 |  TABLE ACCESS BY INDEX ROWID| EMPLOYEES     |      1 |    107 |    107 |00:00:00.01 |       8 |
|*  2 |   INDEX FULL SCAN           | EMPL_EMPID_IX |      1 |    107 |    107 |00:00:00.01 |       3 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   2 - filter("EMPLOYEE_ID" IS NOT NULL)

-- 하나도 빠짐없이 읽는게 나으므로 자동적으로 full scan이 진행된다.

  • INDEX FAST FULL SCAN
      • 모든 LEAF BLOCLK을 읽어낸다.
      • 사용되는 컬럼에 NOT NULL 제약조건 또는 조건식(IS NOT NULL)이 있을때
      • MULTI BLOCK IO
USER01@orcl2> select count(*) from employees where employee_id is NOT NULL;

USER01@orcl2> select employee_id from employees where employee_id IS NOT NULL;
-- 위의 두개는 인덱스만 읽으면 해결되는 두놈

USER01@orcl2> select /*+ INDEX_FFS(e (employee_id))*/ count(*) from employees e where employee_id is NOT NULL;

  COUNT(*)
----------
       107

Elapsed: 00:00:00.00


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  0wwg89s9zc3vw, child number 0
-------------------------------------
select /*+ INDEX_FFS(e (employee_id))*/ count(*) from employees e where
employee_id is NOT NULL

Plan hash value: 21458044

----------------------------------------------------------------------------------------------------
| Id  | Operation             | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers | Reads  |
----------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT      |               |      1 |        |      1 |00:00:00.01 |       4 |      1 |
|   1 |  SORT AGGREGATE       |               |      1 |      1 |      1 |00:00:00.01 |       4 |      1 |
|*  2 |   INDEX FAST FULL SCAN| EMPL_EMPID_IX |      1 |    107 |    107 |00:00:00.01 |       4 |      1 |
----------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - filter("EMPLOYEE_ID" IS NOT NULL)

Elapsed: 00:00:00.01




USER01@orcl2> select /*+ INDEX_FFS(e (employee_id))*/ employee_id from employees e where employee_id IS NOT NULL;

107 rows selected.
Elapsed: 00:00:00.01


USER01@orcl2> @xplan

PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
SQL_ID  412hvhgq0tjwz, child number 0
-------------------------------------
select /*+ INDEX_FFS(e (employee_id))*/ employee_id from employees e
where employee_id IS NOT NULL

Plan hash value: 62351567

------------------------------------------------------------------------------------------------
| Id  | Operation            | Name          | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT     |               |      1 |        |    107 |00:00:00.01 |       6 |
|*  1 |  INDEX FAST FULL SCAN| EMPL_EMPID_IX |      1 |    107 |    107 |00:00:00.01 |       6 |
------------------------------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------

   1 - filter("EMPLOYEE_ID" IS NOT NULL)

Elapsed: 00:00:00.01




클러스터
  • 데이터를 저장하는 방법
  • Index(ed) Cluster

  • Hash Cluster
      • 해시 함수 결과에 따라 행을 검색



Sort 연산자
  • SORT ORDER BY
      • SELECT * FROM EMP ORDER BY SAL
      • 실제 메모리를 할당해서 SORT를 진행
  • SORT AGGREGATE
      • SELECT SUM(SAL) FROM EMP
      • GROUP 함수
      • 실제로 정렬 작업은 하지 않는다.
  • SORT UNIQUE
      • SELECT DNAME FROM DEPT UNION SELECT ENAME FROM EMP
      • SELECT DNAME FROM DEPT UNION ALL SELECT ENAME FROM EMP
          • 결과는 같지만 SORT UNIQUE를 하지 않는다.
          • 즉 결과가 같으면 UNION ALL을 사용하자
  • HASH UNIQUE
      • SELECT DISTINCT(DEPTNO) FROM EMP
      • 정렬 작업을 할 필요가 없다.
  • SORT GROUP BY
      • SELECT DEPTNO, SUM(SAL) FROM EMP GROUP BY DEPTNO ORDER BY DEPTNO
  • HASH GROUP BY
      • SELECT DEPTNO, SUM(SAL) FROM EMP GROUP BY DEPTNO
      • 실제로 정렬 작업은 하지 않는다 다만 DISTINCT작업만 한것.
  • BUFFER SORT
      • SELECT * FROM EMP E, DEPT D WHERE ENAME LIKE 'A%'


INLIST ITERATOR 연산자
  • SELECT * FROM EMP WHERE DEPTNO IN (10,20)
  • 인덱스를 전체 한번읽고 또 따로따로 읽는다.


Count StopKey 연산자
  • SELECT * FROM EMP WHERE ROWNUM = 1