#!/bin/sh
tpipe() {
sleep 3;echo 'user'
sleep 1;echo 'passwd'
sleep 1;echo 'who'
sleep 1;echo 'exit'
sleep 5
}
tpipe | telnet localhost
2009년 6월 15일 월요일
2009년 5월 22일 금요일
DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝
1
DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝
발표자 : 강정식 (xsofter@empal.com)
Team : OracleClub Core Database
2
소개
강정식
(주)LS산전 Oracle ERP Project 개발
(주)LG전자 Oracle GERP Project DB 모니터링 및 Tuning
xsofter@empal.com
3
Online Activity
BLOG http://blog.naver.com/xsoft
4
협조사항
원할한 진행을 위해 질문/답변은 휴식시간과 세미나 종료 후 진행하겠습니다.
5
목차
I. DBMS_XPLAN.DISPLAY
II. 10046 Trace
III. DBMS_XPLAN.DISPLAY_CURSOR
6
SQL TUNING에 대한 질문들
> SQL 튜닝을 하고 싶은데 방법을 모르겠다!
> SQL 튜닝을 하려면 고급 TOOL이 필요하다던데?
> SQL 튜닝을 할 때 Trace를 이용하라던데?
> Trace 읽는 권한이 없어서 볼 수가 없는데 이 경우에는?
7
SQL TUNING에 대한 질문들
DBMS_XPLAN PACKAGE
8
SQL TUNING에 대한 질문들
PL/SQL Developer TOOL
Orange TOOL
9 I. DBMS_XPLAN.DISPLAY INTRODUCTION
DBMS_XPLAN Package?
> EXPLAIN PLAN 구문보다 확장된 정보를 보여줌
> Oracle 9i에서 소개되었으며 Version Up에 따라 기능이 추가됨
> DBMS_XPLAN Package에서 제공하는 Function
- DISPLAY
- DISPLAY_CURSOR
- DISPLAY_AWR
- DISPLAY_SQLSET
- PREPARE_RECORDS
- VALIDATE_FORMAT
> 이 Package를 사용하기 위해서는 아래의 객체에 SELECT 권한이 있어야 함
- V$SESSION
- V$SQL_PLAN
- V$SQL(optional)
- V$SQL_PLAN_STATISTICS_ALL
10 I. DBMS_XPLAN.DISPLAY INTRODUCTION
I. DBMS_XPLAN.DISPLAY
11 I. DBMS_XPLAN.DISPLAY INTRODUCTION
DBMS_XPLAN.DISPLAY
> 단일 SQL문에 대해 예측 실행계획을 보여주는 Function
- Function Parameter
FUNCTION DISPLAY(TABLE_NAME VARCHAR2 DEFAULT 'PLAN_TABLE',
STATEMENT_ID VARCHAR2 DEFAULT NULL,
FORMAT VARCHAR2 DEFAULT 'TYPICAL',
FILTER_PREDS VARCHAR2 DEFAULT NULL)
- 파라미터 설명
. TABLE_NAME: Execution Plan이 저장되는 테이블을 테이블을 지정하며, Defalut는 'PLAN_TABLE'이다.
. STATEMENT_ID: Execution Plan시 SET STATEMENT_ID를 지정한 경우 이를 불러올 수 있다. 값이 NULL일 경우 마지막에 실행된 문장을 불러온다.
. FORMAT
.. BASIC: 가장 기본적인 정보만 보여줌
.. TYPICAL: Format의 Default값인 Typical은 SQL 튜닝에 필요한 Normal한 정보를 보여줌. SQL 튜닝에 가장 유용하게 사용되는 Predicate Information이 제공된다
.. ALL: Typical Format에 Query Block Name과 Column Projection Information이 추가로 제공된다
.. OUTLINE: Typical Format에 추가적으로 Hidden Hint인 Outline Global Hint를 제공한다
.. ADVANCED: ALL Format에 OUTLINE Format를 합친 정보를 제공한다
. FILTER_PREDS: 저장된 PLAN에서 일부 Row 또는 Row Set을 제한하여 출력할 수 있다.
12 I. DBMS_XPLAN.DISPLAY INTRODUCTION
사용방법
I. DBMS_XPLAN.DISPLAY
> SQL*PLUS open
- Oracle Client인 SQL*PLUS를 실행한다.
> EXPLAIN PLAN FOR + SQL;
- 분석하고자 하는 SQL을 'EXPLAIN PLAN FOR' 다음에 넣고 Enter
> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
- SQL이 EXPLAIN 되었으면 그 다음에 원하는 포멧으로 출력한다.
- 위와 같이 하였으면 기본적으로 'PLAN_TABLE'과 'TYPICAL' Format으로 출력하겠다는 의미임
13 I. DBMS_XPLAN.DISPLAY INTRODUCTION
Create Sample Data
CREATE TABLE EMP
(
EMPNO NUMBER(10) NOT NULL,
EMPNO_VARCHAR VARCHAR2(10) NOT NULL
JOB VARCHAR2(9),
HIREDATE DATE,
DEPTNO NUMBER(2);
CREATE TABLE DEPT
(
DEPTNO NUMBER(2),
DNAME VARCHAR2(14),
LOC VARCHAR2(13)
);
> EMP TABLE INDEX
EMP_N1 : DEPTNO
EMP_N2 : HIREDATE
EMP_N3 : EMPNO_VARCHAR
EMP_U1 : EMPNO
> DEPT TABLE INDEX
DEPT_U1 : DEPTNO
JOB 20개 값 그룹
HIREDATE 10로우씩
증가 자리수 * 10
13 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
[EMP 테이블] [DEPT 테이블]
EMPNO / EMPNO_VARCHAR 1,000 만건 순차 증가
Sample
I. DBMS_XPLAN.DISPLAY
SQL> EXPLAIN PLAN FOR
2 SELECT *
3 FROM EMP E
4 WHERE E.EMPNO = 9999999
5 AND E.DEPTNO = 10;
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 3475272958
INTRODUCTION
14 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
15 rows selected.
BASIC Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
FORMAT
지정
▶ BASIC ▷ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
15 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'BASIC'));
----------------------------------------------
| Id | Operation | Name |
----------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP |
| 2 | INDEX UNIQUE SCAN | EMP_U1 |
----------------------------------------------
PLAN
정보
BASIC Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
추가 정보 N/A N/A
설명
16 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
TYPICAL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
FORMAT
지정
▷ BASIC ▶ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
PLAN
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'TYPICAL')); 정보
17 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Predicate Information
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
TYPICAL Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
설명
▷ BASIC ▶ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
18 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
ALL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
FORMAT
지정
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
19 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Query Block Name
추가정보
Predicate Information
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
2 - SEL$1 / E@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
ALL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
FORMAT
지정
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
20 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "E"."EMPNO"[NUMBER,22], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "E".ROWID[ROWID,10], "E"."EMPNO"[NUMBER,22]
추가정보
Column Projection Information
ALL Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
설명
21 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
Query
Block
SQL에서 View, Inline View 등 각각의 집합을 Query Block으로 해석하고 그 이름을 부여함
옵티마이저가 자동으로 이름을 부여하며 그 이름을 주고 싶으면 /*+ QB_NAME(이름) */ 힌트를 사용
Column
Projection
Information
Predicate Information이 WHERE절에 사용되는 조건컬럼만 보여주는 것이라면
Column Projection Information은 해당 Operation에서 사용되는 모든 컬럼을 보여줌
OUTLINE Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▶ OUTLINE ▷ ADVANCED
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'OUTLINE'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
22 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Outline Data
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
추가정보
Predicate Information
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$1" "E"@"SEL$1" ("EMP"."EMPNO"))
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
OPT_PARAM('_optim_peek_user_binds' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
OUTLINE Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▶ OUTLINE ▷ ADVANCED
설명
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
23 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
Outline Data
SQL 튜닝시 가장 강력한 정보 제공
SQL을 수행할 때 옵티마이저가 참고하는 Hidden Hint
SQL에 Hint를 따로 주지 않아도 부여를 하며 여기서 사용되는 대부분의 Hint들은
Query Block Name을 바탕으로 구성함
이 정보가 제공되기 전까지는 기존에 알려진 힌트로만 튜닝을 할 수 있었으나
이를 사용하게 되면서 기존에 튜닝이 불가능하였던 부분까지 가능해짐
Undocument Format이기 때문에 아직까지 활용범위는 적으나 점차 사용할 수 있는 범위가 확대되고 있음
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
BASIC
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
+ TYPICAL + ALL + OUTLINE
24 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
25 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Outline Data
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$1" "E"@"SEL$1" ("EMP"."EMPNO"))
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
OPT_PARAM('_optim_peek_user_binds' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
26 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Query Block Name
추가정보
Predicate Information
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
2 - SEL$1 / E@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
27 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "E"."EMPNO"[NUMBER,22], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "E".ROWID[ROWID,10], "E"."EMPNO"[NUMBER,22]
추가정보
Column Projection Information
I. DBMS_XPLAN.DISPLAY 정리
DBMS_XPLAN.DISPLAY 정리
구분 항목 설명
PLAN 정보
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Rows 예상 Rows
Bytes 예상 Byte
28 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Cost(% CPU) 예상 Cost
Time 예상 수행시간(단위 : 초)
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
Query Block SQL에서 View, Inline View 등 각각의 집합을 Query Block으로 해석하고 그 이름을 부여함
Column Projection
Information
해당 Operation에서 사용되는 모든 컬럼을 보여줌
Outline Data SQL을 수행할 때 옵티마이저가 참고하는 Hidden Hint
I. DBMS_XPLAN.DISPLAY 사례연구
29 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1. 데이터타입 불일치일 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = 111;
튜닝 전
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
30 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 12327 (3)| 00:02:28 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 26 | 12327 (3)| 00:02:28 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("E"."EMPNO_VARCHAR")=111)
1. 데이터타입 불일치일 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = '111';
튜닝 후
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
31 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 26 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_N3 | 1 | | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("E"."EMPNO_VARCHAR"='111')
2. Local Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 전
사례연구
EXPLAIN PLAN FOR
SELECT *
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
32 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 83M| 12387 (4)| 00:02:29 |
| 1 | NESTED LOOPS | | 1998K| 83M| 12387 (4)| 00:02:29 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 18 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | | 0 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | EMP | 1998K| 49M| 12386 (4)| 00:02:29 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=TO_NUMBER(:B1))
4 - filter("E"."DEPTNO"=TO_NUMBER(:B1))
2. Local Hint 사용
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT /*+ INDEX(E EMP_N1) */
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO = :B1;
튜닝 후
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
33 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 83M| 17838 (1)| 00:03:35 |
| 1 | NESTED LOOPS | | 1998K| 83M| 17838 (1)| 00:03:35 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 18 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | | 0 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1998K| 49M| 17837 (1)| 00:03:35 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 2162K| | 4270 (2)| 00:00:52 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=TO_NUMBER(:B1))
5 - access("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 전
사례연구
EXPLAIN PLAN FOR
SELECT *
FROM (SELECT *
FROM (SELECT E.EMPNO,
E.JOB,
D.DEPTNO
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
) DEPTH_1
) LOCAL
34 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE LOCAL.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 26M| 12386 (4)| 00:02:29 |
| 1 | NESTED LOOPS | | 1998K| 26M| 12386 (4)| 00:02:29 |
|* 2 | INDEX UNIQUE SCAN| DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| EMP | 1998K| 20M| 12386 (4)| 00:02:29 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=TO_NUMBER(:B1))
3 - filter("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 후
사례연구
EXPLAIN PLAN FOR
SELECT /*+ INDEX(LOCAL.DEPTH_1.E EMP_N1) */
*
FROM (SELECT *
FROM (SELECT E.EMPNO,
E.JOB,
D.DEPTNO
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
) DEPTH_1
) LOCAL
35 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE LOCAL.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 26M| 17837 (1)| 00:03:35 |
| 1 | NESTED LOOPS | | 1998K| 26M| 17837 (1)| 00:03:35 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1998K| 20M| 17837 (1)| 00:03:35 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 2162K| | 4270 (2)| 00:00:52 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=TO_NUMBER(:B1))
4 - access("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용 목적
I. DBMS_XPLAN.DISPLAY 사례연구
사업장 모델명 출고형태 Case-1 ∨ 조회
사업장 모델명 출고형태
선택
조건
선택
조건
필수
A Program 조건
36 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
∨
I. DBMS_XPLAN.DISPLAY
Simple ERD
사례연구
SELECT *
FROM (SELECT XMI.SEGMENT1 MODEL_CODE,
HCSU.ATTRIBUTE3 SHIP_GROUP_CODE,
OHA.INVOICE_TO_ORG_ID H_BILL_TO_ID
…………
FROM TAB_01 OHA,
TAB_02 OLA,
TAB_03 OTAA,
TAB_04 OTTA,
TAB_05 OTAB,
TAB_06 OTTB,
TAB_07 OOS,
하나의 프로그램에서도Global View를 사용할 때 조건에 따라
효율적인Access를 하기 위해 3개의 Driving Table로 분기가 된다.
3. Global Hint 사용 목적
OLA
OOS
XMI
RTL
OTTB
-H_BILL_TO_ID
(INVOICE_TO_ORG_ID)
- SEGMENT1(MODEL_CODE)
OHA
37 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
TYPE_ID
AND OTTA.TRANSACTION_TYPE_ID = OTAA.TRANSACTION_TYPE_ID
AND OLA.LINE_TYPE_ID = OTTB.TRANSACTION_TYPE_ID
AND OTTB.TRANSACTION_TYPE_ID = OTAB.TRANSACTION_TYPE_ID
AND OHA.ORDER_SOURCE_ID = OOS.ORDER_SOURCE_ID
AND OLA.INVENTORY_ITEM_ID = XMI.INVENTORY_ITEM_ID(+)
AND OLA.SHIP_FROM_ORG_ID = XMI.ORGANIZATION_ID(+)
AND OLA.SHIP_TO_ORG_ID = HCSU.SITE_USE_ID
AND RTL.TERM_ID = OLA.PAYMENT_TERM_ID
AND OLA.LINE_ID = XSN.SOURCE_LINE_TAB_08 XMI,
TAB_09 HCSU,
TAB_10 RTL,
TAB_11 XSN
OTTA
OTAA
HCSU
OTAB
XSN
- SHIP_GROUP_CODE(ATTRIBUTE3)
WHERE OHA.HEADER_ID = OLA.HEADER_ID
AND OHA.ORDER_TYPE_ID = OTTA.TRANSACTION_ID(+)) TEST_V
WHERE TEST_V.SHIP_GROUP_CODE = :B1
AND TEST_V.H_BILL_TO_ID = :B2
AND TEST_V.MODEL_CODE = :B3
I. DBMS_XPLAN.DISPLAY 사례연구
A Program B Program
3. Global Hint 사용 목적
38 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
3개의 Driving Table 존재 4개의 Driving Table 존재
I. DBMS_XPLAN.DISPLAY 사례연구
A Program B Program C Program D Program E Program …………….
APPLICATION
Location
3. Global Hint 사용 목적
39 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
VIEW
DB
Location
View와 같은 DB Object는 Application에서 최적화를 시켜야 한다.
View는 Application에서 접근이 잘 될 수 있도록 구성되어야 한다.
I. DBMS_XPLAN.DISPLAY View를 통한 사례 연구
1 rows 1 rows
1,000만
rows
Table
View
1 rows 1 rows
1,000만
rows
Table
View
40 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
[뷰 침투가 안되어 뷰 안의 1,000만건을 모두 읽는 경우] [뷰 침투가 되어 뷰 안의 1건만 읽는 경우]
구분 내용
조인키
DECODE, NVL, SUBSTR 등의 펑션으로 가공되어선 안된다.
스칼라 서브쿼리라면 FROM절로 내려서 조인으로 연결시켜야 한다.
FUNCTION이라면 FUNCTION안의 로직을 가져와야 한다.
데이터타입 뷰 안의 조인키로 사용되는 데이터타입을 정확히 파악하여 같은 데이터타입으로 연결시켜야 한다.
힌트 뷰 안에는 가급적 Local Hints를 사용하면 안된다.
ALIAS 뷰 안에서 여러 SQL이 UNION ALL로 묶여 있을 경우 Alias 중복을 피해야 한다.
ROWNUM 뷰 안에서는 반드시 ROWNUM 사용을 피해야 한다.
EMP_V
4. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
AND :B2 -- 20090131
;
튜닝 전
View를 통한 사례 연구
(SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
41 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25010 | 439K| 9802 (8)| 00:01:58 |
|* 1 | FILTER | | | | | |
|* 2 | TABLE ACCESS FULL| EMP | 25010 | 439K| 9802 (8)| 00:01:58 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(:B1<=:B2)
2 - filter(TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')>=:B1
AND TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')<=:B2)
4. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE
DEPTNO
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 2009/01/01 00:00:00
튜닝 후
View를 통한 사례 연구
42 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND :B2 -- 2009/01/31 23:59:59
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25010 | 439K| 274 (1)| 00:00:04 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 25010 | 439K| 274 (1)| 00:00:04 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 45019 | | 123 (1)| 00:00:02 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(:B1)<=TO_DATE(:B2))
3 - access("HIREDATE">=:B1 AND "HIREDATE"<=:B2)
EMP_V
5. 뷰 안에 Local Hint가 들어있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM
WHERE EMP_V.EMPNO = :B1
튜닝 전
View를 통한 사례 연구
(SELECT /*+ FULL(EMP) */
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
43 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 9343 (4)| 00:01:53 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 18 | 9343 (4)| 00:01:53 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("EMPNO"=TO_NUMBER(:B1))
5. 뷰 안에 Local Hint가 들어있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM (SELECT --/*+ FULL(EMP) */
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.EMPNO = :B1
튜닝 후
View를 통한 사례 연구
44 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=TO_NUMBER(:B1))
6. 뷰 안에 ROWNUM이 존재할 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT EMP_V.*
FROM (SELECT ROWNUM,
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 전
View를 통한 사례 연구
45 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9993K| 562M| 9255 (3)| 00:01:52 |
| 1 | NESTED LOOPS | | 9993K| 562M| 9255 (3)| 00:01:52 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 6 | 0 (0)| 00:00:01 |
|* 3 | VIEW | | 9993K| 505M| 9255 (3)| 00:01:52 |
| 4 | COUNT | | | | | |
| 5 | TABLE ACCESS FULL| EMP | 9993K| 171M| 9255 (3)| 00:01:52 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
3 - filter("EMP_V"."DEPTNO"=10)
6. 뷰 안에 ROWNUM이 존재할 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT ROWNUM,
EMP_V.*
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 후
View를 통한 사례 연구
46 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 21 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
4 - access("DEPTNO"=10)
I. DBMS_XPLAN.DISPLAY Q & A
47 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
II. 10046 Trace INTRODUCTION
II. 10046 Trace
48 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace INTRODUCTION
10046 Trace?
49 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY
예측정보
50 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
10046 Trace
실측정보
어플리케이션에서 수행하는 각각의 SQL 구문들에 대해 실질적이고
정확한 수행정보를 얻고자 할때 사용하는 방법
이 이벤트는 실제 SQL을 수행하기 때문에 예측 정보가 아닌 실측 정
보를 얻을 수 있다.
10046 Trace?
Trace 파일 및 TKPROF Util
II. 10046 Trace INTRODUCTION
51 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
이 이벤트를 통해 Trace 파일을 얻을 수 있다.
Trace 파일을 직관적으로 볼 수 있도록 TKPROF Util을 이용하여 변환을 한다.
Trace Level
Instance Level
Session Level
Instance에서 수행되는 모든 SQL에 Trace를 걸 수 있으나 서버에 많은 부하 발생
Session에서 수행되는 모든 SQL에 Trace를 거는 방법
일반적으로 사용되는 방법이다.
10046 Trace 사용 방법
자신이 접속한 Session의 SPID(Server Process ID)를 확인한다.
SELECT P.SPID SERVER
FROM V$PROCESS P,
V$SESSION S
WHERE P.ADDR = S.PADDR
AND S.AUDSID = USERENV('SESSIONID');
SERVER
------
218038
II. 10046 Trace INTRODUCTION
52 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
10046 Trace 활성화
ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 1';
10046 Trace LEVEL
LEVEL
설정
항목 설명
LEVEL - 1 기본 정보
LEVEL - 4 기본 정보 + Binding 정보
LEVEL - 8 기본 정보 + Waiting 정보
LEVEL - 12 기본 정보 + Binding 정보 + Waiting 정보
10046 Trace 사용 방법
SQL 수행
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
no rows selected
10046 Trace 비 활성화
II. 10046 Trace INTRODUCTION
53 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
ALTER SESSION SET SQL_TRACE=FALSE;
EXIT;
Trace 파일 확인
USER_DUMP_DEST(UDUMP)에서 SPID.trc 파일 확인
일반적인 UDUMP 파일 경로
$oracle_home/admin/Instance Name/udump/spid.trc
10046 Trace 사용 방법
II. 10046 Trace INTRODUCTION
SPID 확인
Trace 활성화
54 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SQL 수행
Trace 비 활성화
Session 종료
10046 Trace 사용 방법
218038.trc 파일 확인
II. 10046 Trace INTRODUCTION
=====================
PARSING IN CURSOR #2 len=69 dep=0 uid=44 oct=3 lid=44 tim=65620558312435 hv=1079158054 ad='a3a0eaf0'
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
END OF STMT
PARSE #2:c=0,e=4143,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=65620558312421
EXEC #2:c=0,e=159,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65620558312792
직관적으로
보기 어려움
55 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FETCH #2:c=10000,e=3280,p=3,cr=4,cu=0,mis=0,r=0,dep=0,og=1,tim=65620558316229
TKPROF Util 사용하여 파일 변환
tkprof 218038.trc 218038.txt
TKPROF 구문
tkprof tracefile outputfile [options]
Option 설명
SORT = option 명령문 정렬 순서(ex. fchela : fetch 하는데 수행시간이 가장 오래 걸린 SQL로 Descending Sort)
EXPLAIN = username/password 지정된 schema에서 EXPLAIN PLAN을 실행함
SYS = NO user에 의해 실행된 Recursive SQL문의 나열 비활성화
AGGREGATE = NO 다른 user의 동일한 SQL문을 하나의 레코드로 집계하지 않음
WAITS = YES Trace파일에서 발견된 모든 Wait이벤트에 대한 요약 기록 여부
10046 Trace 사용 방법
218038.txt 파일 확인
II. 10046 Trace INTRODUCTION
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
보기
1
56 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 0.000 0.028 3 4 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 0.000 0.031 3 4 0 0
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS BY INDEX ROWID EMP (cr=4 pr=3 pw=0 time=28400 us)
1 INDEX UNIQUE SCAN EMP_U1 (cr=3 pr=2 pw=0 time=22438 us)(Object ID 6485271)
보기
2
보기
3
LEVEL . 1
출력 내용
구분 항목 설명
보기
1
Call
Parse SQL을 Parsing하는 구간
Execute SQL을 실제 수행하는 구간. DML일 경우 이 부분이 표시됨
Fetch SQL을 통해 나온 값을 사용자에게 반환하는 구간
Cpu CPU에서 수행한 시간(단위 : 초)
Elapsed 각 구간에서 시작과 종료까지 총 수행한 시간(단위 : 초)
II. 10046 Trace INTRODUCTION
10046 Trace 사용 방법
상세 설명
57 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Disk Disk에서 Block을 읽은 양(Physical Read)
Query Memory에 Block을 읽은 양(Logical Read
Current 현재의 Session에서 Commit하지 않은 Block을 읽은 양
Rows 각 단계별 액세스한 ROWS
보기
2
Misses in library
cache during parse
Parse 구간에서 해당 SQL을 Library Cache에서 읽지 못하고 잃어버린 횟수
값은 1씩 증가함
값이 1이면 Hard Parse. 0이면 Soft Parse를 의미함
보기
3
cr(consistent read) Logical Block Read
pr(Physical Read) Physical Block Read
pw(Physical Write) Physical Block Write
time 수행시간(단위 - 1 / 1,000,000 초)
II. 10046 Trace INTRODUCTION
LEVEL - 4
Binding 정보 확인 방법 . TKPROF로 변환된 결과가 아닌 Trc파일로 확인
ALTER SESSION SET EVENTS '10046 trace name context forever, level 4';
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
EXEC :B1 := '20090101';
EXEC :B2 := '20090131';
SELECT *
LEVEL
설정
58 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
AND :B2; -- 20090131
EMPNO JOB HIREDATE DEPTNO
---------- ------ ---------------- ----------
7334091 O 20090101 70
7334092 O 20090101 70
..........................................
7334400 O 20090131 70
310 rows selected.
ALTER SESSION SET SQL_TRACE=FALSE;
EXIT;
II. 10046 Trace INTRODUCTION
LEVEL - 4
Trace 파일 확인
=====================
PARSING IN CURSOR #3 len=246 dep=0 uid=44 oct=3 lid=44 tim=65624929564376 hv=3228697289 ad='a2a97a20'
SELECT *
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
59 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND :B2 -- 20090131
END OF STMT
PARSE #3:c=0,e=146,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65624929564368
BINDS #3:
kkscoacd
Bind#0
oacdty=01 mxl=2000(300) mxlc=00 mal=00 scl=00 pre=00
oacflg=03 fl2=1000000 frm=01 csi=871 siz=4000 off=0
kxsbbbfp=110581460 bln=2000 avl=08 flg=05
value="20090101"
Bind#1
oacdty=01 mxl=2000(300) mxlc=00 mal=00 scl=00 pre=00
oacflg=03 fl2=1000000 frm=01 csi=871 siz=0 off=2000
kxsbbbfp=110581c30 bln=2000 avl=08 flg=01
value="20090131"
EXEC #3:c=0,e=308,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65624929564933
*** 2009-04-06 11:37:54.170
FETCH #3:c=13560000,e=13284284,p=0,cr=24385,cu=0,mis=0,r=1,dep=0,og=1,tim=65624942849330
<생략>
첫번째
바인드 값
두번째
바인드 값
해당 SQL
구분자
II. 10046 Trace INTRODUCTION
LEVEL - 8
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
LEVEL
설정
Waiting 정보 확인 방법 . TKPROF로 변환된 결과로 확인
60 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Fetch 1 0.000 0.028 3 4 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 0.000 0.031 3 4 0 0
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS BY INDEX ROWID EMP (cr=4 pr=3 pw=0 time=28400 us)
1 INDEX UNIQUE SCAN EMP_U1 (cr=3 pr=2 pw=0 time=22438 us)(Object ID 6485271)
Wait Event Name Count Wait(sec) Max Wait
-------------------------------------------------- ------- ---------- --------
db file sequential read 3 0.027 0.010
SQL*Net message to client 1 0.000 0.000
SQL*Net message from client 1 0.003 0.003
--------------------------------------------------- ------- --------- --------
Total 5 0.03
Waiting
정보
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
SELECT *
FROM EMP E
WHERE TRIM(E.EMPNO) = 9999999
AND E.DEPTNO = 30;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16684 | 293K| 9386 (4)| 00:01:53 |
|* 1 | TABLE ACCESS FULL| EMP | 16684 | 293K| 9386 (4)| 00:01:53 |
예측정보와 실측정보 비교
예측정보는 16,684 로우 예상
실측정보는 0로우 액세스
예측정보와 실측정보는 예상과 실제 수행
의 차이가 있기 때문에 값이 다를 수 있다.
이 차이점은 Rows, Time 뿐만 아니라
Plan도 다르게 나올 수 있다.
그러므로 정확한 튜닝을 위해서는 10046
Trace를 이용하여 실측정보를 확인해야
한다.
하지만 XPLAN에서는 10046 Trace에서
61 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=30 AND TO_NUMBER(TRIM(TO_CHAR("E"."EMPNO")))=
9999999)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 2.680 5.551 33082 33299 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 2.680 5.554 33082 33299 0 0
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS FULL EMP (cr=33299 pr=33082 pw=0 time=5551325 us)
예측정보는 113초 예상
실측정보는 5.5초 수행
XPLAN Trace
제공하지 않는 Predicate Information을
제공하기 때문에 10046 Trace로만 튜닝
하기에는 한계가 있으므로 양쪽정보를 모
두 참고해야 한다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
단일 SQL vs 다중 SQL
DECLARE
p_deptno NUMBER;
v_job VARCHAR2(20);
v_loc VARCHAR2(20);
BEGIN
p_deptno := 10;
SELECT E.JOB
SELECT E.JOB
FROM
EMP E WHERE E.DEPTNO = :B1 AND ROWNUM = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.01 0.07 13 4 0 1
PL/SQL
수행
Trace
결과
62 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
INTO v_job
FROM EMP E
WHERE E.DEPTNO = p_deptno
AND ROWNUM = 1;
SELECT D.LOC
INTO v_loc
FROM DEPT D
WHERE D.DEPTNO = p_deptno
AND ROWNUM = 1;
END;
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.01 0.07 13 4 0 1
<생략>
SELECT D.LOC
FROM
DEPT D WHERE D.DEPTNO = :B1 AND ROWNUM = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.00 0 2 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.00 0.00 0 2 0 1
<생략>
DBMS_XPLAN.DISPLAY는 단일 SQL만
분석이 가능하나 Trace는 다중 SQL 분석
이 가능하다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
Function 정보
CREATE OR REPLACE FUNCTION
F1(p_num IN NUMBER) RETURN NUMBER IS
v_num NUMBER;
BEGIN
SELECT SUM(E.EMPNO)
INTO v_num
FROM EMP E
WHERE E.DEPTNO = p_num;
RETURN v_num;
END;
SELECT D.DEPTNO,
F1(D.DEPTNO) F_DEPTNO
FROM DEPT D
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.004 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 21.710 25.440 43908 398200 0 9
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Function
생성
Trace
정보
63 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXPLAIN PLAN FOR
SELECT D.DEPTNO,
F1(D.DEPTNO) F_DEPTNO
FROM DEPT D;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
------------------------------------------
| Id | Operation | Name | Rows |
------------------------------------------
| 0 | SELECT STATEMENT | | 9 |
| 1 | TABLE ACCESS FULL| DEPT | 9 |
------------------------------------------
Total 4 21.710 25.445 43908 398200 0 9
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
9 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=129 us)
;
SELECT SUM(E.EMPNO) FROM EMP E WHERE E.DEPTNO = :B1
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 9 0.000 0.004 0 0 0 0
Fetch 9 21.690 25.424 43908 398169 0 9
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 19 21.690 25.429 43908 398169 0 9
예측
정보
Function
안의 내용
확인 가능
DBMS_XPLAN.DISPLAY는 Function의
내용을 볼 수 없으나 Trace는 내용을 확
인할 수 있다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
전체 비교
항목
DBMS_XPLAN
DISPLAY
10046 Trace
수행결과 예측 실측
SQL 수행 1개 1개 이상
64 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Function
수행정보
X O
단계별
통계치
X O
PLAN 정보 O O
추가 정보 O X
Predicate Information
Query Block
Column Projection Information
Outline Data
Parse
Execute
Fetch
II. 10046 Trace 사례연구
65 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace
추출하고자 하는 대상 테이블이 어디인가?
사례연구
SELECT DISTINCT D.*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 18.740 21.832 40358 44244 0 8
1. 성능 관점에서 효율적인 SQL 구성
66 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 18.740 21.835 40358 44244 0 8
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
8 HASH UNIQUE (cr=44244 pr=40358 pw=0 time=21831482 us)
10000000 HASH JOIN (cr=44244 pr=40358 pw=0 time=20004628 us)
9 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=120 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=40358 pw=0 time=109 us)
추출하고자 하는 대상은 DEPT 테이블의 데이터임에도 불구하고
EMP 테이블과 조인을 시도하였다.
결국 두 테이블의 관계가 1 : M 이므로 불필요하게 EMP 테이블을
모두 액세스하고 DISTINCT로 중복 제거를 하였다.
II. 10046 Trace
추출하고자 하는 대상 테이블이 어디인가?
사례연구
SELECT D.*
FROM DEPT D
WHERE EXISTS (SELECT 1
FROM EMP E
WHERE E.DEPTNO = D.DEPTNO);
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
1. 성능 관점에서 효율적인 SQL 구성
추출하고자 하는
대상 테이블만을
FROM절에 위치시키자
67 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Fetch 2 0.000 0.042 7 24 0 8
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 0.000 0.046 7 24 0 8
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
8 NESTED LOOPS SEMI (cr=24 pr=7 pw=0 time=7432 us)
9 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=263 us)
8 INDEX RANGE SCAN EMP_N1 (cr=20 pr=7 pw=0 time=42135 us)(Object ID 6652496)
추출하고자 하는 대상만을 FROM절에 놓고 나머지는 체크만 하기
위해 EXISTS절에 위치시켰으며 이로 인해 수행속도가 대폭 감소되
었다.
II. 10046 Trace
OLTP 화면에서 부분범위처리를 하려면?
사례연구
2. 부분범위처리 튜닝 방법
사업부 이름 조회
사업부 이름 사업부 번호 입사일자 업무팀 이름
68 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
15 ∨
rows
II. 10046 Trace
SQL Trace 확인
사례연구
SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
Trace를 확인한 결과 901건이 추출되었다.
이 중 화면상에 설계된 15건만 부분범위 처리하여
보여주고자 한다.
2. 부분범위처리 튜닝 방법
69 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND D.DNAME = :B1;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 92 43.910 45.473 6989 44244 0 901
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 94 43.910 45.477 6989 44244 0 901
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
901 HASH JOIN (cr=44244 pr=6989 pw=0 time=44110198 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=126 us)
1000007 VIEW (cr=44241 pr=6989 pw=0 time=46107766 us)
1000007 HASH GROUP BY (cr=44241 pr=6989 pw=0 time=45107756 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=6989 pw=0 time=10000130 us)
II. 10046 Trace
ROWNUM 사용 . Trace 내용
사례연구
SELECT *
FROM (SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
최종 SQL에 ROWNUM을 넣은 뒤 인라인 뷰로 만
든 다음 밖에서 화면 설계된 로우수 만큼 추출하는
조건을 준다.
부분범위 처리 조건
2. 부분범위처리 튜닝 방법
. 실행계획에서 모든 조인은 NL 조인이 되어야
한다. 만약 HASH JOIN이 하나라도 있으면 부
분범위처리가 안된다.
. NL 조인이 되더라도 View Merging이 되어야 한
다.
70 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE CNT <= 15;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 3 43.170 42.211 0 44244 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 43.170 42.218 0 44244 0 15
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 VIEW (cr=44244 pr=0 pw=0 time=40881287 us)
901 COUNT (cr=44244 pr=0 pw=0 time=40883966 us)
901 HASH JOIN (cr=44244 pr=0 pw=0 time=40883056 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=131 us)
1000007 VIEW (cr=44241 pr=0 pw=0 time=41880601 us)
1000007 HASH GROUP BY (cr=44241 pr=0 pw=0 time=41880596 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=0 pw=0 time=114 us)
ROWNUM
적용 HASH JOIN이 적용되어
부분범위 처리를 하지 못하고
EMP 테이블을 모두 액세스함
II. 10046 Trace 사례연구
SELECT *
FROM (SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
2. 부분범위처리 튜닝 방법
ROWNUM 사용 . DBMS_XPLAN.DISPLAY 내용
71 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE CNT <= 15;
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 706K| 40M| | 40769 (4)| 00:08:10 |
|* 1 | VIEW | | 706K| 40M| | 40769 (4)| 00:08:10 |
| 2 | COUNT | | | | | | |
|* 3 | HASH JOIN | | 706K| 15M| | 40769 (4)| 00:08:10 |
|* 4 | TABLE ACCESS FULL | DEPT | 1 | 11 | | 3 (0)| 00:00:01 |
| 5 | VIEW | | 3534K| 40M| | 40731 (4)| 00:08:09 |
| 6 | HASH GROUP BY | | 3534K| 43M| 311M| 40731 (4)| 00:08:09 |
| 7 | TABLE ACCESS FULL| EMP | 10M| 124M| | 12240 (3)| 00:02:27 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CNT"<=15)
3 - access("EMP_V"."DEPTNO"="D"."DEPTNO")
4 - filter("D"."DNAME"=:B1)
II. 10046 Trace
힌트 사용 . Trace 내용
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D) USE_NL(D EMP_V) PUSH_PRED(EMP_V) INDEX(EMP_V.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
2. 부분범위처리 튜닝 방법
NL 조인이 되었음에도 불구하고
EMP_V 뷰 안에 GROUP BY가
있어서 View Merging이 안됨
72 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1) WHERE CNT <= 15;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 3 32.600 31.880 0 44245 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 32.600 31.886 0 44245 0 15
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 VIEW (cr=44245 pr=0 pw=0 time=30636573 us)
901 COUNT (cr=44245 pr=0 pw=0 time=30639256 us)
901 NESTED LOOPS (cr=44245 pr=0 pw=0 time=30638349 us)
1 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=204 us)
901 VIEW (cr=44241 pr=0 pw=0 time=30637328 us)
1000007 SORT GROUP BY (cr=44241 pr=0 pw=0 time=31636297 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=0 pw=0 time=113 us)
Nested Loop 확인
II. 10046 Trace
힌트 사용 . DBMS_XPLAN.DISPLAY 내용
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D) USE_NL(D EMP_V) PUSH_PRED(EMP_V) INDEX(EMP_V.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
2. 부분범위처리 튜닝 방법
73 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1) WHERE CNT <= 15;
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 706K| 40M| | 40734 (4)| 00:08:09 |
|* 1 | VIEW | | 706K| 40M| | 40734 (4)| 00:08:09 |
| 2 | COUNT | | | | | | |
| 3 | NESTED LOOPS | | 706K| 15M| | 40734 (4)| 00:08:09 |
|* 4 | TABLE ACCESS FULL | DEPT | 1 | 11 | | 3 (0)| 00:00:01 |
|* 5 | VIEW | | 706K| 8284K| | 40731 (4)| 00:08:09 |
| 6 | SORT GROUP BY | | 3534K| 43M| 311M| 40731 (4)| 00:08:09 |
| 7 | TABLE ACCESS FULL| EMP | 10M| 124M| | 12240 (3)| 00:02:27 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CNT"<=15)
4 - filter("D"."DNAME"=:B1)
5 - filter("EMP_V"."DEPTNO"="D"."DEPTNO")
II. 10046 Trace
그룹함수를 분석함수로 대체
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D)
USE_NL(D EMP_V)
PUSH_PRED(EMP_V)
INDEX(EMP_V.INLINE_EMP.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB
2. 부분범위처리 튜닝 방법
74 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM (SELECT INLINE_EMP.DEPTNO,
INLINE_EMP.HIREDATE,
INLINE_EMP.MIN_JOB
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
E.JOB MIN_JOB,
ROW_NUMBER() OVER(PARTITION BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')
ORDER BY E.JOB) GUBN
FROM EMP E) INLINE_EMP
WHERE INLINE_EMP.GUBN = 1) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE ROWNUM <= 15;
분석함수를 사용하여
View Merging이 되도록
유도함
II. 10046 Trace
그룹함수를 분석함수로 대체 . DBMS_XPLAN.DISPLAY 내용
사례연구
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 15 | 765 | | 4 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | NESTED LOOPS | | 1111K| 54M| | 4 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | DEPT | 1 | 14 | | 3 (0)| 00:00:01 |
|* 4 | VIEW PUSHED PREDICATE | | 3 | 111 | | 1 (0)| 00:00:01 |
|* 5 | WINDOW SORT PUSHED RANK | | 2001K| 24M| 91M| 26239 (2)| 00:05:15 |
2. 부분범위처리 튜닝 방법
75 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 2001K| 24M| | 16592 (1)| 00:03:20 |
|* 7 | INDEX RANGE SCAN | EMP_N1 | 2018K| | | 3986 (2)| 00:00:48 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=15)
3 - filter("D"."DNAME"=:B1)
4 - filter("INLINE_EMP"."GUBN"=1)
5 - filter(ROW_NUMBER() OVER ( PARTITION BY
"E"."DEPTNO",TO_CHAR(INTERNAL_FUNCTION("E"."HIREDATE"),'YYYYMMDD')
ORDER BY "E"."JOB")<=1)
7 - access("E"."DEPTNO"="D"."DEPTNO") 조인 조건이 뷰 안으로
침투가 된 것이 확인됨
II. 10046 Trace
그룹함수를 분석함수로 대체 . Trace 내용
사례연구
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.010 0 0 0 0
Fetch 3 0.060 0.055 18 59 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 0.060 0.068 18 59 0 15
Misses in library cache during parse: 1
2. 부분범위처리 튜닝 방법
76 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 COUNT STOPKEY (cr=59 pr=18 pw=0 time=53933 us)
15 NESTED LOOPS (cr=59 pr=18 pw=0 time=53924 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=85 us)
15 VIEW PUSHED PREDICATE (cr=56 pr=18 pw=0 time=53834 us)
132 WINDOW SORT PUSHED RANK (cr=56 pr=18 pw=0 time=54082 us)
9000 TABLE ACCESS BY INDEX ROWID EMP (cr=56 pr=18 pw=0 time=18068 us)
9000 INDEX RANGE SCAN EMP_N1 (cr=21 pr=18 pw=0 time=9053 us)(Object ID 6720703)
View Merging이 되어
PUSHED PREDICATE
실행계획이 나타남
II. 10046 Trace Q & A
77 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
III. DBMS_XPLAN.DISPLAY_CURSOR
III. DBMS_XPLAN.DISPLAY_CURSOR
INTRODUCTION
78 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR?
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
79 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY
10046 Trace
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
예측정보이므로 정확한 튜닝결과를 알 수 없다.
실측정보이므로 강력하지만 Trc 파일을 얻으려면 서버에 접근해야 함
하지만 일반 사이트에서는 개발자들에게 서버 접근 권한을 주지 않음
80 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR
그러므로 개발자들이 Trc 파일을 이용하기에는 버거운 상태임
그럼 개발자들는 튜닝을 할 수 없는 것인가?
해결방법은 DBMS_XPLAN.DISPLAY_CURSOR
DISPLAY가 예측치를 보여주는 거라면 DISPLAY_CURSOR는 실측치
를 보여줌
DBMS_XPLAN.DISPLAY_CURSOR
III. DBMS_XPLAN.DISPLAY_CURSOR
단일 SQL문에 대해 실제 수행된 실행계획을 보여주는 Function
FUNCTION DISPLAY_CURSOR(SQL_ID VARCHAR2 DEFAULT NULL,
CURSOR_CHILD_NO INTEGER DEFAULT 0,
FORMAT VARCHAR2 DEFAULT 'TYPICAL')
Function Parameter
파라미터 설명
INTRODUCTION
81 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
파라미터 설명
TABLE_NAME
실제 수행된 SQL의 SQL_ID 값을 입력하면 해당 SQL의 실행계획을 볼 수 있다.
SQL_ID 값은 V$SQL, V$SQLAREA에서 확인할 수 있다.
SQL_ID 값을 명시하지 않으면 해당 세션의 마지막에 실행된 문장을 의미한다.
STATEMENT_ID
해당 SQL_ID의 CHILD NUMBER 값을 지정한다.
CURSOR_CHILD_NO 값을 명시하지 않으면 해당 SQL_ID의 첫번째 CURSOR_CHILD_NO 값을 가져온다.
FORMAT 저장된 PLAN을 어떤 Format으로 보여줄 지 결정하는 파라미터
FORMAT
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 FORMAT 내용
예측
내용
BASIC DBMS_XPLAN.DISPLAY 포멧과 같은 내용
TYPICAL DBMS_XPLAN.DISPLAY 포멧과 같은 내용
ALL DBMS_XPLAN.DISPLAY 포멧과 같은 내용
OUTLINE DBMS_XPLAN.DISPLAY 포멧과 같은 내용
ADVANCED DBMS_XPLAN.DISPLAY 포멧과 같은 내용
82 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
실측
내용
ALLSTATS
실제 액세스한 로우수와 수행시간 그리고 CR, PR, PW 정보를
보여준다.
수행횟수에 따라 누적된 값을 보여준다.
ALLSTATS LAST
실제 액세스한 로우수와 수행시간 그리고 CR, PR, PW 정보를
보여준다.
가장 최근에 수행된 값만 보여준다.
ADVANCED ALLSTATS
LAST
DBMS_XPLAN.DISPLAY_CURSOR에서 지원하는 모든 Format의
정보를 보여준다.
사용방법
PLAN_STATISTICS 정보는 다음의 조건 중 하나를 만족해야 기록됨
이 Package를 사용하기 위해서는 아래의 객체에 SELECT 권한이 있어야 함
V$SESSION
V$SQL_PLAN
V$SQL(optional)
V$SQL_PLAN_STATISTICS_ALL
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
83 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
'STATISTICS_LEVEL' Parameter 값을 ALL로 변경한 경우
'_ROWSOURCE_EXECUTION_STATISTICS' Parameter 값을 TRUE로 변경한 경우
GATHER_PLAN_STATISTICS HINT를 사용할 때, 10g부터 지원
WINDOW 환경에서 SQL*PLUS를 사용할 때
이 경우에 DBMS_XPLAN.DISPLAY_CURSOR 정보를 보려면 다음의 구문 사용해야
SET SERVEROUTPUT OFF;
Runtime Execution Plan 확인방법
이 펑션은 이미 수행된 SQL의 PLAN을 확인할 수 있는 장점이 있다.
이미 수행된 SQL은 V$SQL을 조회하여 확인할 수 있다
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Sample
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
1. SQL 실행
84 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
no rows selected
SELECT SUBSTR(SQL_TEXT, 1, 30) SQL_TEXT,
SQL_ID,
CHILD_NUMBER
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT * FROM EMP E%'
;
SQL_TEXT SQL_ID CHILD_NUMBER
------------------------------ ------------- ------------
SELECT * FROM EMP E WHERE E ak7vxhj055996 0
2. V$SQL에서 SQL_ID 확인
Runtime Execution Plan 확인방법
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('ak7vxhj055996', 0, 'ALLSTATS LAST'));
-------------------------------------------------------
| Id | Operation | Name | E-Rows |
-------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 |
-------------------------------------------------------
Predicate Information (identified by operation id):
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
3. DBMS_XPLAN.DISPLAY_CURSOR 조회
85 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
Note
-----
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
수행한 SQL이 다음의 조건을 충족하지 않았기 때문에 기록이 안됨
'STATISTICS_LEVEL' Parameter 값을 ALL로 변경한 경우
'_ROWSOURCE_EXECUTION_STATISTICS' Parameter 값을 TRUE로 변경한 경우
GATHER_PLAN_STATISTICS HINT를 사용할 때, 10g부터 지원
Runtime Execution Plan 확인방법
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
;
no rows selected
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
4. STATISTICS_LEVEL 파라미터 값 변경 이후 추가 수행
세션 레벨의
파라미터 변경
86 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT SUBSTR(SQL_TEXT, 1, 30) SQL_TEXT,
SQL_ID,
CHILD_NUMBER
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT * FROM EMP E%'
;
SQL_TEXT SQL_ID CHILD_NUMBER
------------------------------ ------------- ------------
SELECT * FROM EMP E WHERE E ak7vxhj055996 0
SELECT * FROM EMP E WHERE E ak7vxhj055996 1
동일한 SQL을 'STATISTICS_LEVEL' 값을 변경하여 수행하였기 때문에
CHILD_NUMBER 값으로 구분
CHILD_NUMBER
추가 확인
Runtime Execution Plan 확인방법
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('ak7vxhj055996', 1, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 0 |00:00:00.01 | 4 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | 1 |00:00:00.01 | 3 |
---------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
5. DBMS_XPLAN.DISPLAY_CURSOR 다시 조회
추가
정보
-------------------------------------------------------
실제
수행한
결과
87 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| Id | Operation | Name | E-Rows |
-------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 |
-------------------------------------------------------
예측
결과
예측 실행계획과 실제 실행계획 비교
A-Rows, A-Time, Buffer 추가 정보 보여줌
E : Estimate, A : Actual
ALLSTATS Format
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 항목 설명
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Starts 각 Operation을 수행한 회수(만약 NL Join이라면 Looping한 회수)
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
88 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
PLAN 정보 E-Rows 각 Operation에서 예측한 로우수
A-Rows 각 Operation에서 실제 액세스한 로우수
A-Time 각 Operation에서 실제 수행된 시간(단위 : 초)
Buffer 각 Operation에서 실제 읽은 Logical Block
Read 각 Operation에서 실제 읽은 Physical Block
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보
이 Format은 Starts, A-Rows, Buffer의 출력값을 누적하여 보여준다.
ALLSTATS Format
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ USE_NL(E D) */
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO IN (10, 20, 30)
;
Sample
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
89 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS'));
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 999 |00:00:00.26 | 156 | 10 |
| 2 | NESTED LOOPS | | 1 | 2701K| 1003 |00:00:07.22 | 86 | 6 |
| 3 | INLIST ITERATOR | | 1 | | 3 |00:00:00.03 | 9 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 3 |00:00:00.03 | 9 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | 3 |00:00:00.02 | 6 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| 999 |00:00:00.21 | 77 | 4 |
-------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(("D"."DEPTNO"=10 OR "D"."DEPTNO"=20 OR "D"."DEPTNO"=30))
6 - access("E"."DEPTNO"="D"."DEPTNO")
filter(("E"."DEPTNO"=10 OR "E"."DEPTNO"=20 OR "E"."DEPTNO"=30))
ALLSTATS Format
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 999 |00:00:00.26 | 156 | 10 |
| 2 | NESTED LOOPS | | 1 | 2701K| 1003 |00:00:07.22 | 86 | 6 |
| 3 | INLIST ITERATOR | | 1 | | 3 |00:00:00.03 | 9 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 3 |00:00:00.03 | 9 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | 3 |00:00:00.02 | 6 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| 999 |00:00:00.21 | 77 | 4 |
-------------------------------------------------------------------------------------------------------------
Sample
1회
수행
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
90 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 2 | 900K| 1998 |00:00:00.28 | 312 | 10 |
| 2 | NESTED LOOPS | | 2 | 2701K| 2006 |00:00:07.25 | 172 | 6 |
| 3 | INLIST ITERATOR | | 2 | | 6 |00:00:00.03 | 18 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 6 | 3 | 6 |00:00:00.03 | 18 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 6 | 3 | 6 |00:00:00.02 | 12 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 6 | 906K| 1998 |00:00:00.22 | 154 | 4 |
-------------------------------------------------------------------------------------------------------------
2회
수행
누적
정보
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 항목 설명
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Starts 각 Operation을 수행한 회수(만약 NL Join이라면 Looping한 회수)
ALLSTATS LAST Format ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
91 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
PLAN 정보 E-Rows 각 Operation에서 예측한 로우수
A-Rows 각 Operation에서 실제 액세스한 로우수
A-Time 각 Operation에서 실제 수행된 시간(단위 : 초)
Buffer 각 Operation에서 실제 읽은 Logical Block
Read 각 Operation에서 실제 읽은 Physical Block
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보
LAST Format은 Starts, A-Rows, Buffer의 출력값을 최근 수행한 결과만 보여준다.
ADVANCED ALLSTATS LAST Format
ADVANCED ALLSTATS LAST Format은
DBMS_XPLAN Package에서 제공하는 모든 Format의 결정판.
LAST이므로 가장 최근에 수행된 결과만 출력
Sample
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ USE_NL(E D) */
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
92 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO IN (10, 20, 30)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 22M| 9673 (1)| 00:01:57 | 999 |00:00:00.02 | 156 |
| 2 | NESTED LOOPS | | 1 | 2701K| 113M| 21467 (2)| 00:04:18 | 1003 |00:00:00.01 | 86 |
| 3 | INLIST ITERATOR | | 1 | | | | | 3 |00:00:00.01 | 9 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 54 | 2 (0)| 00:00:01 | 3 |00:00:00.01 | 9 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | | 1 (0)| 00:00:01 | 3 |00:00:00.01 | 6 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| | 4008 (2)| 00:00:49 | 999 |00:00:00.01 | 77 |
-----------------------------------------------------------------------------------------------------------------------------------
Sample
ADVANCED ALLSTATS LAST Format
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
4 - SEL$1 / D@SEL$1
5 - SEL$1 / D@SEL$1
6 - SEL$1 / E@SEL$1
Outline Data
-------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
93 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_optim_peek_user_binds' 'false')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_RS_ASC(@"SEL$1" "D"@"SEL$1" ("DEPT"."DEPTNO"))
INDEX(@"SEL$1" "E"@"SEL$1" ("EMP"."DEPTNO"))
LEADING(@"SEL$1" "D"@"SEL$1" "E"@"SEL$1")
USE_NL(@"SEL$1" "E"@"SEL$1")
END_OUTLINE_DATA
*/
Sample
ADVANCED ALLSTATS LAST Format
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(("D"."DEPTNO"=10 OR "D"."DEPTNO"=20 OR "D"."DEPTNO"=30))
6 - access("E"."DEPTNO"="D"."DEPTNO")
filter(("E"."DEPTNO"=10 OR "E"."DEPTNO"=20 OR "E"."DEPTNO"=30))
Column Projection Information (identified by operation id):
-----------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
94 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1 - "E"."EMPNO"[NUMBER,22], "E"."EMPNO_VARCHAR"[VARCHAR2,40], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45], "E".ROWID[ROWID,10],
"E"."DEPTNO"[NUMBER,22]
3 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45]
4 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45]
5 - "D".ROWID[ROWID,10], "D"."DEPTNO"[NUMBER,22]
6 - "E".ROWID[ROWID,10], "E"."DEPTNO"[NUMBER,22]
10046 Trace vs DBMS_XPLAN.DISPLAY_CURSOR 비교
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT *
FROM EMP E
WHERE TRIM(E.EMPNO) = 9999999
AND E.DEPTNO = 30
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
CURSOR : A-Rows
Trace : Rows
CURSOR : A-Time
Trace : time
CURSOR : Buffers
Trace : cr
CURSOR : Reads
Trace : pr
95 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
|* 1 | TABLE ACCESS FULL| EMP | 1 | 16659 | 0 |00:00:05.62 | 33299 | 33083 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("E"."DEPTNO"=30 AND TO_NUMBER(TRIM(TO_CHAR("E"."EMPNO")))=9999999))
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 2.680 5.551 33082 33299 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 2.680 5.554 33082 33299 0 0
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS FULL EMP (cr=33299 pr=33082 pw=0 time=5551325 us)
DISPLAY vs 10046 Trace vs DISPLAY_CURSOR 비교
전체 비교
항목
DBMS_XPLAN
DISPLAY
10046 Trace
DBMS_XPLAN
DISPLAY_CURSOR
수행결과 예측 실측 실측
SQL 수행 1개 1개 이상 1개
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
96 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Function 수행정보 X O X
단계별
통계치
X O X
PLAN 정보 O O O
추가정보 O X O
Predicate Information
Query Block
Column Projection Information
Outline Data
Parse
Execute
Fetch
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
97 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1. 데이터타입 불일치일 경우
튜닝 전
사례연구
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = 111;
III. DBMS_XPLAN.DISPLAY_CURSOR
SET SERVEROUTPUT OFF
SET LINESIZE 2000
ALTER SESSION SET STATISTICS_LEVEL = ALL;
98 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS FULL| EMP | 1 | 1 | 1 |00:00:13.92 | 44242 | 43323 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("E"."EMPNO_VARCHAR")=111)
1. 데이터타입 불일치일 경우
튜닝 후
사례연구
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = '111';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR
99 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 1 |00:00:00.01 | 5 | 3 |
|* 2 | INDEX RANGE SCAN | EMP_N3 | 1 | 1 | 1 |00:00:00.01 | 4 | 2 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("E"."EMPNO_VARCHAR"='111')
2. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
EXEC :B1 := '20090101';
EXEC :B2 := '20090131';
튜닝 전
SELECT *
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
100 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1
AND :B2;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 300 |00:00:29.34 | 44261 | 43950 |
|* 2 | TABLE ACCESS FULL| EMP | 1 | 24979 | 300 |00:00:29.34 | 44261 | 43950 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(:B1<=:B2)
2 - filter((TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')>=:B1 AND
TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')<=:B2))
2. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
EXEC :B1 := '20090101 00:00:00';
EXEC :B2 := '20090131 23:59:59';
튜닝 후
SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
101 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD HH24:MI:SS')
AND TO_DATE(:B2, 'YYYYMMDD HH24:MI:SS');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 310 |00:00:00.01 | 49 | 2 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 24979 | 310 |00:00:00.01 | 49 | 2 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 310 |00:00:00.01 | 25 | 2 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(:B1,'YYYYMMDD HH24:MI:SS')<=TO_DATE(:B2,'YYYYMMDD HH24:MI:SS'))
3 - access("HIREDATE">=TO_DATE(:B1,'YYYYMMDD HH24:MI:SS') AND
"HIREDATE"<=TO_DATE(:B2,'YYYYMMDD HH24:MI:SS'))
3. 뷰 안에 ROWNUM이 존재할 경우
ALTER SESSION SET STATISTICS_LEVEL = ALL;
튜닝 전
SELECT EMP_V.*
FROM (SELECT ROWNUM,
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
102 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS | | 1 | 9991K| 9 |00:00:25.47 | 44243 | 7482 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 3 | VIEW | | 1 | 9991K| 9 |00:00:25.47 | 44242 | 7482 |
| 4 | COUNT | | 1 | | 10M|00:00:10.00 | 44242 | 7482 |
| 5 | TABLE ACCESS FULL| EMP | 1 | 9991K| 10M|00:00:10.00 | 44242 | 7482 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
3 - filter("EMP_V"."DEPTNO"=10)
3. 뷰 안에 ROWNUM이 존재할 경우
SELECT ROWNUM,
EMP_V.*
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 후
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
103 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------
| 1 | COUNT | | 1 | | 9 |00:00:00.01 | 7 |
| 2 | NESTED LOOPS | | 1 | 1 | 9 |00:00:00.01 | 7 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 9 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 1 | 1 | 9 |00:00:00.01 | 4 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=10)
5 - access("DEPTNO"=10)
4. OR 조건이 사용될 경우
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
VAR B1 NUMBER;
VAR B2 VARCHAR2(100);
VAR B3 VARCHAR2(100);
튜닝 전
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
104 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXEC :B1 := 10;
EXEC :B2 := '20090401';
EXEC :B3 := '20090402';
SELECT *
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
4. OR 조건이 사용될 경우
SELECT *
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
튜닝 전
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
------------------------------------------------------------------------------------
105 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS FULL| EMP | 1 | 2021K| 29 |00:00:08.84 | 44242 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("E"."DEPTNO"=:B1 OR ("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')
AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))))
4. OR 조건이 사용될 경우
SElECT *
FROM EMP E
WHERE E.DEPTNO = :B1
AND :B1 IS NOT NULL
1차 튜닝 . UNION ALL 분리
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SElECT *
FROM EMP E
WHERE E.HIREDATE BETWEEN :B2
AND :B3
AND :B1 IS NULL;
UNION ALL
106 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 1 | UNION-ALL | | 1 | | 9 |00:00:07.85 | 44242 |
|* 2 | FILTER | | 1 | | 9 |00:00:07.85 | 44242 |
|* 3 | TABLE ACCESS FULL | EMP | 1 | 2506K| 9 |00:00:07.85 | 44242 |
|* 4 | FILTER | | 1 | | 0 |00:00:00.01 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 0 | 25065 | 0 |00:00:00.01 | 0 |
|* 6 | INDEX RANGE SCAN | EMP_N2 | 0 | 45525 | 0 |00:00:00.01 | 0 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:B1 IS NOT NULL)
3 - filter("E"."DEPTNO"=:B1)
4 - filter((TO_DATE(:B2,'YYYYMMDD')<=TO_DATE(:B3,'YYYYMMDD') AND :B1 IS NULL))
6 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND
"E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4. OR 조건이 사용될 경우
SElECT /*+ INDEX(E EMP_N1) */
*
FROM EMP E
WHERE E.DEPTNO = :B1
AND :B1 IS NOT NULL
UNION ALL
SElECT *
FROM EMP E
WHERE E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
AND :B1 IS NULL;
1차 튜닝 . UNION ALL 분리 > 힌트 사용
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
107 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-----------------------------------------------------------------------------------------------------------
| 1 | UNION-ALL | | 1 | | 9 |00:00:00.03 | 6 | 3 |
|* 2 | FILTER | | 1 | | 9 |00:00:00.03 | 6 | 3 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 2506K| 9 |00:00:00.03 | 6 | 3 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 1 | 2506K| 9 |00:00:00.02 | 4 | 2 |
|* 5 | FILTER | | 1 | | 0 |00:00:00.01 | 0 | 0 |
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 0 | 25065 | 0 |00:00:00.01 | 0 | 0 |
|* 7 | INDEX RANGE SCAN | EMP_N2 | 0 | 45525 | 0 |00:00:00.01 | 0 | 0 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:B1 IS NOT NULL)
4 - access("E"."DEPTNO"=:B1)
5 - filter((TO_DATE(:B2,'YYYYMMDD')<=TO_DATE(:B3,'YYYYMMDD') AND :B1 IS NULL))
7 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용
108 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:01.96 | 44250 | 2 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 25065 | 20 |00:00:00.03 | 9 | 2 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 45525 | 20 |00:00:00.03 | 5 | 2 |
|* 4 | TABLE ACCESS FULL | EMP | 1 | 2500K| 9 |00:00:07.93 | 44241 | 0 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4 - filter(("E"."DEPTNO"=:B1 AND (LNNVL("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')) OR
LNNVL("E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD')))))
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 확인
Query Block Name 사용 방법
@ + Query Block Name Object Alias
Ex) SEL$1_2 / E@SEL$1_2
@SEL$1_2 E@SEL$1_2
109 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:05.30 | 44250 | 4174 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 25065 | 20 |00:00:00.01 | 9 | 0 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 45525 | 20 |00:00:00.01 | 5 | 0 |
|* 4 | TABLE ACCESS FULL | EMP | 1 | 2500K| 9 |00:00:05.30 | 44241 | 4174 |
----------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1_1 / E@SEL$1
3 - SEL$1_1 / E@SEL$1
4 - SEL$1_2 / E@SEL$1_2
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 확인
Outline Data
-------------
110 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_optim_peek_user_binds' 'false')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
OUTLINE_LEAF(@"SEL$1_1")
USE_CONCAT(@"SEL$1" 8)
OUTLINE_LEAF(@"SEL$1_2")
OUTLINE(@"SEL$1")
INDEX_RS_ASC(@"SEL$1_1" "E"@"SEL$1" ("EMP"."HIREDATE"))
FULL(@"SEL$1_2" "E"@"SEL$1_2")
END_OUTLINE_DATA
*/
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT
INDEX(@SEL$1_2 E@SEL$1_2 EMP_N1) */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 사용
111 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:00.01 | 13 | 8 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 24979 | 20 |00:00:00.01 | 9 | 5 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.01 | 5 | 3 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 2491K| 9 |00:00:00.01 | 4 | 3 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 1 | 2497K| 9 |00:00:00.01 | 3 | 3 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4 - filter((LNNVL("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')) OR
LNNVL("E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))))
5 - access("E"."DEPTNO"=:B1)
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
VAR B3 NUMBER;
EXEC :B1 := '00010101';
EXEC :B2 := '00010102';
112 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXEC :B3 := 10;
SELECT *
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SELECT *
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
113 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 2 | MERGE JOIN SEMI | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 3 | NESTED LOOPS | | 1 | 9 |00:00:08.72 | 44243 | 43938 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 5 | TABLE ACCESS FULL | EMP | 1 | 9 |00:00:08.72 | 44242 | 43938 |
|* 6 | SORT UNIQUE | | 9 | 9 |00:00:00.02 | 4 | 2 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 9 |00:00:00.02 | 4 | 2 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 20 |00:00:00.02 | 3 | 2 |
----------------------------------------------------------------------------------------------------
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 2 | MERGE JOIN SEMI | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 3 | NESTED LOOPS | | 1 | 9 |00:00:08.72 | 44243 | 43938 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 5 | TABLE ACCESS FULL | EMP | 1 | 9 |00:00:08.72 | 44242 | 43938 |
|* 6 | SORT UNIQUE | | 9 | 9 |00:00:00.02 | 4 | 2 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 9 |00:00:00.02 | 4 | 2 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 20 |00:00:00.02 | 3 | 2 |
----------------------------------------------------------------------------------------------------
114 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1F949E82
4 - SEL$1F949E82 / D@SEL$2
5 - SEL$1F949E82 / E_1@SEL$2
7 - SEL$1F949E82 / E_2@SEL$3
8 - SEL$1F949E82 / E_2@SEL$3
Outline Data
-------------
/*+
INDEX(@"SEL$1F949E82" "D"@"SEL$2" ("DEPT"."DEPTNO"))
FULL(@"SEL$1F949E82" "E_1"@"SEL$2")
INDEX_RS_ASC(@"SEL$1F949E82" "E_2"@"SEL$3" ("EMP"."HIREDATE"))
LEADING(@"SEL$1F949E82" "D"@"SEL$2" "E_1"@"SEL$2" "E_2"@"SEL$3")
USE_NL(@"SEL$1F949E82" "E_1"@"SEL$2")
USE_MERGE(@"SEL$1F949E82" "E_2"@"SEL$3")
END_OUTLINE_DATA
*/
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SELECT /*+ LEADING(@SEL$1F949E82 D@SEL$2 E_2@SEL$3 E_1@SEL$2) */
*
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
1차 튜닝 . Query Block Name을 이용하여 액세스 순서 조정
115 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
--------------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 9 |00:00:06.92 | 44247 | 43959 |
|* 2 | HASH JOIN | | 1 | 3899M| 9 |00:00:06.92 | 44247 | 43959 |
| 3 | NESTED LOOPS | | 1 | 6245 | 1 |00:00:00.05 | 5 | 3 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
| 5 | SORT UNIQUE | | 1 | 6245 | 1 |00:00:00.05 | 4 | 3 |
|* 6 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 6245 | 9 |00:00:00.05 | 4 | 3 |
|* 7 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.05 | 3 | 3 |
|* 8 | TABLE ACCESS FULL | EMP | 1 | 2497K| 9 |00:00:06.87 | 44242 | 43956 |
--------------------------------------------------------------------------------------------------------------
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . Query Block Name을 이용하여 인덱스 유도
SELECT /*+ LEADING(@SEL$1F949E82 D@SEL$2 E_2@SEL$3 E_1@SEL$2) USE_NL(@SEL$1F949E82 E_1@SEL$2) */
*
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
116 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 9 |00:00:00.01 | 11 | 3 |
| 2 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 624K| 9 |00:00:00.01 | 11 | 3 |
| 3 | NESTED LOOPS | | 1 | 3899M| 11 |00:00:00.01 | 9 | 3 |
| 4 | NESTED LOOPS | | 1 | 6245 | 1 |00:00:00.01 | 5 | 0 |
|* 5 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
| 6 | SORT UNIQUE | | 1 | 6245 | 1 |00:00:00.01 | 4 | 0 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 6245 | 9 |00:00:00.01 | 4 | 0 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.01 | 3 | 0 |
|* 9 | INDEX RANGE SCAN | EMP_N1 | 1 | 624K| 9 |00:00:00.01 | 4 | 3 |
---------------------------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR Q & A
117 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
SQL 성능에 대처하는 방법
SQL 성능에 대처하는 방법
118 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SQL 튜닝을 하고 싶은데 방법을 모르겠다!
SQL 튜닝을 하려면 고급 TOOL이 필요하다던데?
SQL 튜닝을 할 때 Trace를 이용하라던데?
Trace 읽는 권한이 없어서 볼 수가 없는데 이 경우에는?
SQL 성능에 대처하는 방법
119 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR
Package
수고하셨습니다!!!
120 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝
발표자 : 강정식 (xsofter@empal.com)
Team : OracleClub Core Database
2
소개
강정식
(주)LS산전 Oracle ERP Project 개발
(주)LG전자 Oracle GERP Project DB 모니터링 및 Tuning
xsofter@empal.com
3
Online Activity
BLOG http://blog.naver.com/xsoft
4
협조사항
원할한 진행을 위해 질문/답변은 휴식시간과 세미나 종료 후 진행하겠습니다.
5
목차
I. DBMS_XPLAN.DISPLAY
II. 10046 Trace
III. DBMS_XPLAN.DISPLAY_CURSOR
6
SQL TUNING에 대한 질문들
> SQL 튜닝을 하고 싶은데 방법을 모르겠다!
> SQL 튜닝을 하려면 고급 TOOL이 필요하다던데?
> SQL 튜닝을 할 때 Trace를 이용하라던데?
> Trace 읽는 권한이 없어서 볼 수가 없는데 이 경우에는?
7
SQL TUNING에 대한 질문들
DBMS_XPLAN PACKAGE
8
SQL TUNING에 대한 질문들
PL/SQL Developer TOOL
Orange TOOL
9 I. DBMS_XPLAN.DISPLAY INTRODUCTION
DBMS_XPLAN Package?
> EXPLAIN PLAN 구문보다 확장된 정보를 보여줌
> Oracle 9i에서 소개되었으며 Version Up에 따라 기능이 추가됨
> DBMS_XPLAN Package에서 제공하는 Function
- DISPLAY
- DISPLAY_CURSOR
- DISPLAY_AWR
- DISPLAY_SQLSET
- PREPARE_RECORDS
- VALIDATE_FORMAT
> 이 Package를 사용하기 위해서는 아래의 객체에 SELECT 권한이 있어야 함
- V$SESSION
- V$SQL_PLAN
- V$SQL(optional)
- V$SQL_PLAN_STATISTICS_ALL
10 I. DBMS_XPLAN.DISPLAY INTRODUCTION
I. DBMS_XPLAN.DISPLAY
11 I. DBMS_XPLAN.DISPLAY INTRODUCTION
DBMS_XPLAN.DISPLAY
> 단일 SQL문에 대해 예측 실행계획을 보여주는 Function
- Function Parameter
FUNCTION DISPLAY(TABLE_NAME VARCHAR2 DEFAULT 'PLAN_TABLE',
STATEMENT_ID VARCHAR2 DEFAULT NULL,
FORMAT VARCHAR2 DEFAULT 'TYPICAL',
FILTER_PREDS VARCHAR2 DEFAULT NULL)
- 파라미터 설명
. TABLE_NAME: Execution Plan이 저장되는 테이블을 테이블을 지정하며, Defalut는 'PLAN_TABLE'이다.
. STATEMENT_ID: Execution Plan시 SET STATEMENT_ID를 지정한 경우 이를 불러올 수 있다. 값이 NULL일 경우 마지막에 실행된 문장을 불러온다.
. FORMAT
.. BASIC: 가장 기본적인 정보만 보여줌
.. TYPICAL: Format의 Default값인 Typical은 SQL 튜닝에 필요한 Normal한 정보를 보여줌. SQL 튜닝에 가장 유용하게 사용되는 Predicate Information이 제공된다
.. ALL: Typical Format에 Query Block Name과 Column Projection Information이 추가로 제공된다
.. OUTLINE: Typical Format에 추가적으로 Hidden Hint인 Outline Global Hint를 제공한다
.. ADVANCED: ALL Format에 OUTLINE Format를 합친 정보를 제공한다
. FILTER_PREDS: 저장된 PLAN에서 일부 Row 또는 Row Set을 제한하여 출력할 수 있다.
12 I. DBMS_XPLAN.DISPLAY INTRODUCTION
사용방법
I. DBMS_XPLAN.DISPLAY
> SQL*PLUS open
- Oracle Client인 SQL*PLUS를 실행한다.
> EXPLAIN PLAN FOR + SQL;
- 분석하고자 하는 SQL을 'EXPLAIN PLAN FOR' 다음에 넣고 Enter
> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
- SQL이 EXPLAIN 되었으면 그 다음에 원하는 포멧으로 출력한다.
- 위와 같이 하였으면 기본적으로 'PLAN_TABLE'과 'TYPICAL' Format으로 출력하겠다는 의미임
13 I. DBMS_XPLAN.DISPLAY INTRODUCTION
Create Sample Data
CREATE TABLE EMP
(
EMPNO NUMBER(10) NOT NULL,
EMPNO_VARCHAR VARCHAR2(10) NOT NULL
JOB VARCHAR2(9),
HIREDATE DATE,
DEPTNO NUMBER(2);
CREATE TABLE DEPT
(
DEPTNO NUMBER(2),
DNAME VARCHAR2(14),
LOC VARCHAR2(13)
);
> EMP TABLE INDEX
EMP_N1 : DEPTNO
EMP_N2 : HIREDATE
EMP_N3 : EMPNO_VARCHAR
EMP_U1 : EMPNO
> DEPT TABLE INDEX
DEPT_U1 : DEPTNO
JOB 20개 값 그룹
HIREDATE 10로우씩
증가 자리수 * 10
13 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
[EMP 테이블] [DEPT 테이블]
EMPNO / EMPNO_VARCHAR 1,000 만건 순차 증가
Sample
I. DBMS_XPLAN.DISPLAY
SQL> EXPLAIN PLAN FOR
2 SELECT *
3 FROM EMP E
4 WHERE E.EMPNO = 9999999
5 AND E.DEPTNO = 10;
Explained.
SQL> SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
Plan hash value: 3475272958
INTRODUCTION
14 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
PLAN_TABLE_OUTPUT
--------------------------------------------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
15 rows selected.
BASIC Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
FORMAT
지정
▶ BASIC ▷ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
15 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'BASIC'));
----------------------------------------------
| Id | Operation | Name |
----------------------------------------------
| 0 | SELECT STATEMENT | |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP |
| 2 | INDEX UNIQUE SCAN | EMP_U1 |
----------------------------------------------
PLAN
정보
BASIC Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
추가 정보 N/A N/A
설명
16 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
TYPICAL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
FORMAT
지정
▷ BASIC ▶ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
PLAN
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'TYPICAL')); 정보
17 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Predicate Information
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
TYPICAL Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
설명
▷ BASIC ▶ TYPICAL ▷ALL ▷ OUTLINE ▷ADVANCED
18 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
ALL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
FORMAT
지정
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
19 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Query Block Name
추가정보
Predicate Information
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
2 - SEL$1 / E@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
ALL Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
FORMAT
지정
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ALL'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
20 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "E"."EMPNO"[NUMBER,22], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "E".ROWID[ROWID,10], "E"."EMPNO"[NUMBER,22]
추가정보
Column Projection Information
ALL Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
▷ BASIC ▷ TYPICAL ▶ ALL ▷ OUTLINE ▷ ADVANCED
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
설명
21 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
Query
Block
SQL에서 View, Inline View 등 각각의 집합을 Query Block으로 해석하고 그 이름을 부여함
옵티마이저가 자동으로 이름을 부여하며 그 이름을 주고 싶으면 /*+ QB_NAME(이름) */ 힌트를 사용
Column
Projection
Information
Predicate Information이 WHERE절에 사용되는 조건컬럼만 보여주는 것이라면
Column Projection Information은 해당 Operation에서 사용되는 모든 컬럼을 보여줌
OUTLINE Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▶ OUTLINE ▷ ADVANCED
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'OUTLINE'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
22 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Outline Data
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
추가정보
Predicate Information
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$1" "E"@"SEL$1" ("EMP"."EMPNO"))
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
OPT_PARAM('_optim_peek_user_binds' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
OUTLINE Format
I. DBMS_XPLAN.DISPLAY INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▶ OUTLINE ▷ ADVANCED
설명
구분 항목 설명
PLAN 정보
ID 각 Operation의 ID. *가 있는 경우 추가 정보란에 해당 ID의 정보를 보여줌
Operation 로우 단위의 액세스 정보를 보여줌
Name 액세스 하는 Object의 정보를 보여줌
Rows 각 Operation에서 예상하는 Rows
Bytes 각 Operation에서 예상하는 Byte
Cost(% CPU) 각 Oepration에서 예상하는 Cost(괄호안의 내용은 CPU Cost의 예상치)
23 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Time 각 Operation에서 예상하는 수행시간
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
SQL 튜닝 시 가장 필요한 정보이며 가장 깅력한 정보임
개발자들이 반드시 알아야 하고 이해하고 있어야 하는 정보
10046 Trace에서도 보여주지 못하는 정보임
Outline Data
SQL 튜닝시 가장 강력한 정보 제공
SQL을 수행할 때 옵티마이저가 참고하는 Hidden Hint
SQL에 Hint를 따로 주지 않아도 부여를 하며 여기서 사용되는 대부분의 Hint들은
Query Block Name을 바탕으로 구성함
이 정보가 제공되기 전까지는 기존에 알려진 힌트로만 튜닝을 할 수 있었으나
이를 사용하게 되면서 기존에 튜닝이 불가능하였던 부분까지 가능해짐
Undocument Format이기 때문에 아직까지 활용범위는 적으나 점차 사용할 수 있는 범위가 확대되고 있음
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
BASIC
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
+ TYPICAL + ALL + OUTLINE
24 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
25 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Outline Data
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Outline Data
-------------
/*+
BEGIN_OUTLINE_DATA
INDEX_RS_ASC(@"SEL$1" "E"@"SEL$1" ("EMP"."EMPNO"))
OUTLINE_LEAF(@"SEL$1")
ALL_ROWS
OPT_PARAM('_optim_peek_user_binds' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
IGNORE_OPTIM_EMBEDDED_HINTS
END_OUTLINE_DATA
*/
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
26 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
추가정보
Query Block Name
추가정보
Predicate Information
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
2 - SEL$1 / E@SEL$1
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
ADVANCED Format
I. DBMS_XPLAN.DISPLAY
Sample
INTRODUCTION
▷ BASIC ▷ TYPICAL ▷ ALL ▷ OUTLINE ▶ ADVANCED
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
PLAN
정보
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY(NULL, NULL, 'ADVANCED'));
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
FORMAT
지정
27 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Column Projection Information (identified by operation id):
-----------------------------------------------------------
1 - "E"."EMPNO"[NUMBER,22], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "E".ROWID[ROWID,10], "E"."EMPNO"[NUMBER,22]
추가정보
Column Projection Information
I. DBMS_XPLAN.DISPLAY 정리
DBMS_XPLAN.DISPLAY 정리
구분 항목 설명
PLAN 정보
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Rows 예상 Rows
Bytes 예상 Byte
28 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Cost(% CPU) 예상 Cost
Time 예상 수행시간(단위 : 초)
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보를 보여줌
Query Block SQL에서 View, Inline View 등 각각의 집합을 Query Block으로 해석하고 그 이름을 부여함
Column Projection
Information
해당 Operation에서 사용되는 모든 컬럼을 보여줌
Outline Data SQL을 수행할 때 옵티마이저가 참고하는 Hidden Hint
I. DBMS_XPLAN.DISPLAY 사례연구
29 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1. 데이터타입 불일치일 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = 111;
튜닝 전
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
30 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 12327 (3)| 00:02:28 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 26 | 12327 (3)| 00:02:28 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("E"."EMPNO_VARCHAR")=111)
1. 데이터타입 불일치일 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = '111';
튜닝 후
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
31 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 26 | 4 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 26 | 4 (0)| 00:00:01 |
|* 2 | INDEX RANGE SCAN | EMP_N3 | 1 | | 3 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("E"."EMPNO_VARCHAR"='111')
2. Local Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 전
사례연구
EXPLAIN PLAN FOR
SELECT *
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
32 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 83M| 12387 (4)| 00:02:29 |
| 1 | NESTED LOOPS | | 1998K| 83M| 12387 (4)| 00:02:29 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 18 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | | 0 (0)| 00:00:01 |
|* 4 | TABLE ACCESS FULL | EMP | 1998K| 49M| 12386 (4)| 00:02:29 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=TO_NUMBER(:B1))
4 - filter("E"."DEPTNO"=TO_NUMBER(:B1))
2. Local Hint 사용
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT /*+ INDEX(E EMP_N1) */
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO = :B1;
튜닝 후
사례연구
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
33 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 83M| 17838 (1)| 00:03:35 |
| 1 | NESTED LOOPS | | 1998K| 83M| 17838 (1)| 00:03:35 |
| 2 | TABLE ACCESS BY INDEX ROWID| DEPT | 1 | 18 | 1 (0)| 00:00:01 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | | 0 (0)| 00:00:01 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1998K| 49M| 17837 (1)| 00:03:35 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 2162K| | 4270 (2)| 00:00:52 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=TO_NUMBER(:B1))
5 - access("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 전
사례연구
EXPLAIN PLAN FOR
SELECT *
FROM (SELECT *
FROM (SELECT E.EMPNO,
E.JOB,
D.DEPTNO
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
) DEPTH_1
) LOCAL
34 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE LOCAL.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 26M| 12386 (4)| 00:02:29 |
| 1 | NESTED LOOPS | | 1998K| 26M| 12386 (4)| 00:02:29 |
|* 2 | INDEX UNIQUE SCAN| DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL| EMP | 1998K| 20M| 12386 (4)| 00:02:29 |
------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=TO_NUMBER(:B1))
3 - filter("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용
I. DBMS_XPLAN.DISPLAY
튜닝 후
사례연구
EXPLAIN PLAN FOR
SELECT /*+ INDEX(LOCAL.DEPTH_1.E EMP_N1) */
*
FROM (SELECT *
FROM (SELECT E.EMPNO,
E.JOB,
D.DEPTNO
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
) DEPTH_1
) LOCAL
35 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE LOCAL.DEPTNO = :B1;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1998K| 26M| 17837 (1)| 00:03:35 |
| 1 | NESTED LOOPS | | 1998K| 26M| 17837 (1)| 00:03:35 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1998K| 20M| 17837 (1)| 00:03:35 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 2162K| | 4270 (2)| 00:00:52 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=TO_NUMBER(:B1))
4 - access("E"."DEPTNO"=TO_NUMBER(:B1))
3. Global Hint 사용 목적
I. DBMS_XPLAN.DISPLAY 사례연구
사업장 모델명 출고형태 Case-1 ∨ 조회
사업장 모델명 출고형태
선택
조건
선택
조건
필수
A Program 조건
36 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
∨
I. DBMS_XPLAN.DISPLAY
Simple ERD
사례연구
SELECT *
FROM (SELECT XMI.SEGMENT1 MODEL_CODE,
HCSU.ATTRIBUTE3 SHIP_GROUP_CODE,
OHA.INVOICE_TO_ORG_ID H_BILL_TO_ID
…………
FROM TAB_01 OHA,
TAB_02 OLA,
TAB_03 OTAA,
TAB_04 OTTA,
TAB_05 OTAB,
TAB_06 OTTB,
TAB_07 OOS,
하나의 프로그램에서도Global View를 사용할 때 조건에 따라
효율적인Access를 하기 위해 3개의 Driving Table로 분기가 된다.
3. Global Hint 사용 목적
OLA
OOS
XMI
RTL
OTTB
-H_BILL_TO_ID
(INVOICE_TO_ORG_ID)
- SEGMENT1(MODEL_CODE)
OHA
37 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
TYPE_ID
AND OTTA.TRANSACTION_TYPE_ID = OTAA.TRANSACTION_TYPE_ID
AND OLA.LINE_TYPE_ID = OTTB.TRANSACTION_TYPE_ID
AND OTTB.TRANSACTION_TYPE_ID = OTAB.TRANSACTION_TYPE_ID
AND OHA.ORDER_SOURCE_ID = OOS.ORDER_SOURCE_ID
AND OLA.INVENTORY_ITEM_ID = XMI.INVENTORY_ITEM_ID(+)
AND OLA.SHIP_FROM_ORG_ID = XMI.ORGANIZATION_ID(+)
AND OLA.SHIP_TO_ORG_ID = HCSU.SITE_USE_ID
AND RTL.TERM_ID = OLA.PAYMENT_TERM_ID
AND OLA.LINE_ID = XSN.SOURCE_LINE_TAB_08 XMI,
TAB_09 HCSU,
TAB_10 RTL,
TAB_11 XSN
OTTA
OTAA
HCSU
OTAB
XSN
- SHIP_GROUP_CODE(ATTRIBUTE3)
WHERE OHA.HEADER_ID = OLA.HEADER_ID
AND OHA.ORDER_TYPE_ID = OTTA.TRANSACTION_ID(+)) TEST_V
WHERE TEST_V.SHIP_GROUP_CODE = :B1
AND TEST_V.H_BILL_TO_ID = :B2
AND TEST_V.MODEL_CODE = :B3
I. DBMS_XPLAN.DISPLAY 사례연구
A Program B Program
3. Global Hint 사용 목적
38 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
3개의 Driving Table 존재 4개의 Driving Table 존재
I. DBMS_XPLAN.DISPLAY 사례연구
A Program B Program C Program D Program E Program …………….
APPLICATION
Location
3. Global Hint 사용 목적
39 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
VIEW
DB
Location
View와 같은 DB Object는 Application에서 최적화를 시켜야 한다.
View는 Application에서 접근이 잘 될 수 있도록 구성되어야 한다.
I. DBMS_XPLAN.DISPLAY View를 통한 사례 연구
1 rows 1 rows
1,000만
rows
Table
View
1 rows 1 rows
1,000만
rows
Table
View
40 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
[뷰 침투가 안되어 뷰 안의 1,000만건을 모두 읽는 경우] [뷰 침투가 되어 뷰 안의 1건만 읽는 경우]
구분 내용
조인키
DECODE, NVL, SUBSTR 등의 펑션으로 가공되어선 안된다.
스칼라 서브쿼리라면 FROM절로 내려서 조인으로 연결시켜야 한다.
FUNCTION이라면 FUNCTION안의 로직을 가져와야 한다.
데이터타입 뷰 안의 조인키로 사용되는 데이터타입을 정확히 파악하여 같은 데이터타입으로 연결시켜야 한다.
힌트 뷰 안에는 가급적 Local Hints를 사용하면 안된다.
ALIAS 뷰 안에서 여러 SQL이 UNION ALL로 묶여 있을 경우 Alias 중복을 피해야 한다.
ROWNUM 뷰 안에서는 반드시 ROWNUM 사용을 피해야 한다.
EMP_V
4. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
AND :B2 -- 20090131
;
튜닝 전
View를 통한 사례 연구
(SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
41 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
---------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25010 | 439K| 9802 (8)| 00:01:58 |
|* 1 | FILTER | | | | | |
|* 2 | TABLE ACCESS FULL| EMP | 25010 | 439K| 9802 (8)| 00:01:58 |
---------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(:B1<=:B2)
2 - filter(TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')>=:B1
AND TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')<=:B2)
4. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE
DEPTNO
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 2009/01/01 00:00:00
튜닝 후
View를 통한 사례 연구
42 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND :B2 -- 2009/01/31 23:59:59
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 25010 | 439K| 274 (1)| 00:00:04 |
|* 1 | FILTER | | | | | |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 25010 | 439K| 274 (1)| 00:00:04 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 45019 | | 123 (1)| 00:00:02 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(:B1)<=TO_DATE(:B2))
3 - access("HIREDATE">=:B1 AND "HIREDATE"<=:B2)
EMP_V
5. 뷰 안에 Local Hint가 들어있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM
WHERE EMP_V.EMPNO = :B1
튜닝 전
View를 통한 사례 연구
(SELECT /*+ FULL(EMP) */
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
43 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 9343 (4)| 00:01:53 |
|* 1 | TABLE ACCESS FULL| EMP | 1 | 18 | 9343 (4)| 00:01:53 |
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("EMPNO"=TO_NUMBER(:B1))
5. 뷰 안에 Local Hint가 들어있는 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT *
FROM (SELECT --/*+ FULL(EMP) */
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.EMPNO = :B1
튜닝 후
View를 통한 사례 연구
44 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 18 | 3 (0)| 00:00:01 |
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | | 2 (0)| 00:00:01 |
--------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("EMPNO"=TO_NUMBER(:B1))
6. 뷰 안에 ROWNUM이 존재할 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT EMP_V.*
FROM (SELECT ROWNUM,
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 전
View를 통한 사례 연구
45 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
--------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 9993K| 562M| 9255 (3)| 00:01:52 |
| 1 | NESTED LOOPS | | 9993K| 562M| 9255 (3)| 00:01:52 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 6 | 0 (0)| 00:00:01 |
|* 3 | VIEW | | 9993K| 505M| 9255 (3)| 00:01:52 |
| 4 | COUNT | | | | | |
| 5 | TABLE ACCESS FULL| EMP | 9993K| 171M| 9255 (3)| 00:01:52 |
--------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
3 - filter("EMP_V"."DEPTNO"=10)
6. 뷰 안에 ROWNUM이 존재할 경우
I. DBMS_XPLAN.DISPLAY
EXPLAIN PLAN FOR
SELECT ROWNUM,
EMP_V.*
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 후
View를 통한 사례 연구
46 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
----------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
----------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | 21 | 3 (0)| 00:00:01 |
| 1 | NESTED LOOPS | | 1 | 21 | 3 (0)| 00:00:01 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 3 | 0 (0)| 00:00:01 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 18 | 3 (0)| 00:00:01 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 1 | | 2 (0)| 00:00:01 |
----------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
4 - access("DEPTNO"=10)
I. DBMS_XPLAN.DISPLAY Q & A
47 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
II. 10046 Trace INTRODUCTION
II. 10046 Trace
48 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace INTRODUCTION
10046 Trace?
49 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY
예측정보
50 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
10046 Trace
실측정보
어플리케이션에서 수행하는 각각의 SQL 구문들에 대해 실질적이고
정확한 수행정보를 얻고자 할때 사용하는 방법
이 이벤트는 실제 SQL을 수행하기 때문에 예측 정보가 아닌 실측 정
보를 얻을 수 있다.
10046 Trace?
Trace 파일 및 TKPROF Util
II. 10046 Trace INTRODUCTION
51 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
이 이벤트를 통해 Trace 파일을 얻을 수 있다.
Trace 파일을 직관적으로 볼 수 있도록 TKPROF Util을 이용하여 변환을 한다.
Trace Level
Instance Level
Session Level
Instance에서 수행되는 모든 SQL에 Trace를 걸 수 있으나 서버에 많은 부하 발생
Session에서 수행되는 모든 SQL에 Trace를 거는 방법
일반적으로 사용되는 방법이다.
10046 Trace 사용 방법
자신이 접속한 Session의 SPID(Server Process ID)를 확인한다.
SELECT P.SPID SERVER
FROM V$PROCESS P,
V$SESSION S
WHERE P.ADDR = S.PADDR
AND S.AUDSID = USERENV('SESSIONID');
SERVER
------
218038
II. 10046 Trace INTRODUCTION
52 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
10046 Trace 활성화
ALTER SESSION SET EVENTS '10046 TRACE NAME CONTEXT FOREVER, LEVEL 1';
10046 Trace LEVEL
LEVEL
설정
항목 설명
LEVEL - 1 기본 정보
LEVEL - 4 기본 정보 + Binding 정보
LEVEL - 8 기본 정보 + Waiting 정보
LEVEL - 12 기본 정보 + Binding 정보 + Waiting 정보
10046 Trace 사용 방법
SQL 수행
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10;
no rows selected
10046 Trace 비 활성화
II. 10046 Trace INTRODUCTION
53 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
ALTER SESSION SET SQL_TRACE=FALSE;
EXIT;
Trace 파일 확인
USER_DUMP_DEST(UDUMP)에서 SPID.trc 파일 확인
일반적인 UDUMP 파일 경로
$oracle_home/admin/Instance Name/udump/spid.trc
10046 Trace 사용 방법
II. 10046 Trace INTRODUCTION
SPID 확인
Trace 활성화
54 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SQL 수행
Trace 비 활성화
Session 종료
10046 Trace 사용 방법
218038.trc 파일 확인
II. 10046 Trace INTRODUCTION
=====================
PARSING IN CURSOR #2 len=69 dep=0 uid=44 oct=3 lid=44 tim=65620558312435 hv=1079158054 ad='a3a0eaf0'
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
END OF STMT
PARSE #2:c=0,e=4143,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=1,tim=65620558312421
EXEC #2:c=0,e=159,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65620558312792
직관적으로
보기 어려움
55 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FETCH #2:c=10000,e=3280,p=3,cr=4,cu=0,mis=0,r=0,dep=0,og=1,tim=65620558316229
TKPROF Util 사용하여 파일 변환
tkprof 218038.trc 218038.txt
TKPROF 구문
tkprof tracefile outputfile [options]
Option 설명
SORT = option 명령문 정렬 순서(ex. fchela : fetch 하는데 수행시간이 가장 오래 걸린 SQL로 Descending Sort)
EXPLAIN = username/password 지정된 schema에서 EXPLAIN PLAN을 실행함
SYS = NO user에 의해 실행된 Recursive SQL문의 나열 비활성화
AGGREGATE = NO 다른 user의 동일한 SQL문을 하나의 레코드로 집계하지 않음
WAITS = YES Trace파일에서 발견된 모든 Wait이벤트에 대한 요약 기록 여부
10046 Trace 사용 방법
218038.txt 파일 확인
II. 10046 Trace INTRODUCTION
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
보기
1
56 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 0.000 0.028 3 4 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 0.000 0.031 3 4 0 0
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS BY INDEX ROWID EMP (cr=4 pr=3 pw=0 time=28400 us)
1 INDEX UNIQUE SCAN EMP_U1 (cr=3 pr=2 pw=0 time=22438 us)(Object ID 6485271)
보기
2
보기
3
LEVEL . 1
출력 내용
구분 항목 설명
보기
1
Call
Parse SQL을 Parsing하는 구간
Execute SQL을 실제 수행하는 구간. DML일 경우 이 부분이 표시됨
Fetch SQL을 통해 나온 값을 사용자에게 반환하는 구간
Cpu CPU에서 수행한 시간(단위 : 초)
Elapsed 각 구간에서 시작과 종료까지 총 수행한 시간(단위 : 초)
II. 10046 Trace INTRODUCTION
10046 Trace 사용 방법
상세 설명
57 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Disk Disk에서 Block을 읽은 양(Physical Read)
Query Memory에 Block을 읽은 양(Logical Read
Current 현재의 Session에서 Commit하지 않은 Block을 읽은 양
Rows 각 단계별 액세스한 ROWS
보기
2
Misses in library
cache during parse
Parse 구간에서 해당 SQL을 Library Cache에서 읽지 못하고 잃어버린 횟수
값은 1씩 증가함
값이 1이면 Hard Parse. 0이면 Soft Parse를 의미함
보기
3
cr(consistent read) Logical Block Read
pr(Physical Read) Physical Block Read
pw(Physical Write) Physical Block Write
time 수행시간(단위 - 1 / 1,000,000 초)
II. 10046 Trace INTRODUCTION
LEVEL - 4
Binding 정보 확인 방법 . TKPROF로 변환된 결과가 아닌 Trc파일로 확인
ALTER SESSION SET EVENTS '10046 trace name context forever, level 4';
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
EXEC :B1 := '20090101';
EXEC :B2 := '20090131';
SELECT *
LEVEL
설정
58 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
AND :B2; -- 20090131
EMPNO JOB HIREDATE DEPTNO
---------- ------ ---------------- ----------
7334091 O 20090101 70
7334092 O 20090101 70
..........................................
7334400 O 20090131 70
310 rows selected.
ALTER SESSION SET SQL_TRACE=FALSE;
EXIT;
II. 10046 Trace INTRODUCTION
LEVEL - 4
Trace 파일 확인
=====================
PARSING IN CURSOR #3 len=246 dep=0 uid=44 oct=3 lid=44 tim=65624929564376 hv=3228697289 ad='a2a97a20'
SELECT *
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1 -- 20090101
59 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND :B2 -- 20090131
END OF STMT
PARSE #3:c=0,e=146,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65624929564368
BINDS #3:
kkscoacd
Bind#0
oacdty=01 mxl=2000(300) mxlc=00 mal=00 scl=00 pre=00
oacflg=03 fl2=1000000 frm=01 csi=871 siz=4000 off=0
kxsbbbfp=110581460 bln=2000 avl=08 flg=05
value="20090101"
Bind#1
oacdty=01 mxl=2000(300) mxlc=00 mal=00 scl=00 pre=00
oacflg=03 fl2=1000000 frm=01 csi=871 siz=0 off=2000
kxsbbbfp=110581c30 bln=2000 avl=08 flg=01
value="20090131"
EXEC #3:c=0,e=308,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,tim=65624929564933
*** 2009-04-06 11:37:54.170
FETCH #3:c=13560000,e=13284284,p=0,cr=24385,cu=0,mis=0,r=1,dep=0,og=1,tim=65624942849330
<생략>
첫번째
바인드 값
두번째
바인드 값
해당 SQL
구분자
II. 10046 Trace INTRODUCTION
LEVEL - 8
ALTER SESSION SET EVENTS '10046 trace name context forever, level 8';
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
LEVEL
설정
Waiting 정보 확인 방법 . TKPROF로 변환된 결과로 확인
60 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Fetch 1 0.000 0.028 3 4 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 0.000 0.031 3 4 0 0
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS BY INDEX ROWID EMP (cr=4 pr=3 pw=0 time=28400 us)
1 INDEX UNIQUE SCAN EMP_U1 (cr=3 pr=2 pw=0 time=22438 us)(Object ID 6485271)
Wait Event Name Count Wait(sec) Max Wait
-------------------------------------------------- ------- ---------- --------
db file sequential read 3 0.027 0.010
SQL*Net message to client 1 0.000 0.000
SQL*Net message from client 1 0.003 0.003
--------------------------------------------------- ------- --------- --------
Total 5 0.03
Waiting
정보
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
SELECT *
FROM EMP E
WHERE TRIM(E.EMPNO) = 9999999
AND E.DEPTNO = 30;
--------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes | Cost (%CPU)| Time |
--------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 16684 | 293K| 9386 (4)| 00:01:53 |
|* 1 | TABLE ACCESS FULL| EMP | 16684 | 293K| 9386 (4)| 00:01:53 |
예측정보와 실측정보 비교
예측정보는 16,684 로우 예상
실측정보는 0로우 액세스
예측정보와 실측정보는 예상과 실제 수행
의 차이가 있기 때문에 값이 다를 수 있다.
이 차이점은 Rows, Time 뿐만 아니라
Plan도 다르게 나올 수 있다.
그러므로 정확한 튜닝을 위해서는 10046
Trace를 이용하여 실측정보를 확인해야
한다.
하지만 XPLAN에서는 10046 Trace에서
61 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("E"."DEPTNO"=30 AND TO_NUMBER(TRIM(TO_CHAR("E"."EMPNO")))=
9999999)
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 2.680 5.551 33082 33299 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 2.680 5.554 33082 33299 0 0
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS FULL EMP (cr=33299 pr=33082 pw=0 time=5551325 us)
예측정보는 113초 예상
실측정보는 5.5초 수행
XPLAN Trace
제공하지 않는 Predicate Information을
제공하기 때문에 10046 Trace로만 튜닝
하기에는 한계가 있으므로 양쪽정보를 모
두 참고해야 한다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
단일 SQL vs 다중 SQL
DECLARE
p_deptno NUMBER;
v_job VARCHAR2(20);
v_loc VARCHAR2(20);
BEGIN
p_deptno := 10;
SELECT E.JOB
SELECT E.JOB
FROM
EMP E WHERE E.DEPTNO = :B1 AND ROWNUM = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.01 0.07 13 4 0 1
PL/SQL
수행
Trace
결과
62 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
INTO v_job
FROM EMP E
WHERE E.DEPTNO = p_deptno
AND ROWNUM = 1;
SELECT D.LOC
INTO v_loc
FROM DEPT D
WHERE D.DEPTNO = p_deptno
AND ROWNUM = 1;
END;
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.01 0.07 13 4 0 1
<생략>
SELECT D.LOC
FROM
DEPT D WHERE D.DEPTNO = :B1 AND ROWNUM = 1
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.00 0.00 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 1 0.00 0.00 0 2 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 3 0.00 0.00 0 2 0 1
<생략>
DBMS_XPLAN.DISPLAY는 단일 SQL만
분석이 가능하나 Trace는 다중 SQL 분석
이 가능하다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
Function 정보
CREATE OR REPLACE FUNCTION
F1(p_num IN NUMBER) RETURN NUMBER IS
v_num NUMBER;
BEGIN
SELECT SUM(E.EMPNO)
INTO v_num
FROM EMP E
WHERE E.DEPTNO = p_num;
RETURN v_num;
END;
SELECT D.DEPTNO,
F1(D.DEPTNO) F_DEPTNO
FROM DEPT D
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.004 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 21.710 25.440 43908 398200 0 9
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Function
생성
Trace
정보
63 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXPLAIN PLAN FOR
SELECT D.DEPTNO,
F1(D.DEPTNO) F_DEPTNO
FROM DEPT D;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
------------------------------------------
| Id | Operation | Name | Rows |
------------------------------------------
| 0 | SELECT STATEMENT | | 9 |
| 1 | TABLE ACCESS FULL| DEPT | 9 |
------------------------------------------
Total 4 21.710 25.445 43908 398200 0 9
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
9 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=129 us)
;
SELECT SUM(E.EMPNO) FROM EMP E WHERE E.DEPTNO = :B1
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 9 0.000 0.004 0 0 0 0
Fetch 9 21.690 25.424 43908 398169 0 9
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 19 21.690 25.429 43908 398169 0 9
예측
정보
Function
안의 내용
확인 가능
DBMS_XPLAN.DISPLAY는 Function의
내용을 볼 수 없으나 Trace는 내용을 확
인할 수 있다.
II. 10046 Trace INTRODUCTION
DBMS_XPLAN.DISPLAY vs 10046 Trace 비교
전체 비교
항목
DBMS_XPLAN
DISPLAY
10046 Trace
수행결과 예측 실측
SQL 수행 1개 1개 이상
64 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Function
수행정보
X O
단계별
통계치
X O
PLAN 정보 O O
추가 정보 O X
Predicate Information
Query Block
Column Projection Information
Outline Data
Parse
Execute
Fetch
II. 10046 Trace 사례연구
65 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
II. 10046 Trace
추출하고자 하는 대상 테이블이 어디인가?
사례연구
SELECT DISTINCT D.*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 2 18.740 21.832 40358 44244 0 8
1. 성능 관점에서 효율적인 SQL 구성
66 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 18.740 21.835 40358 44244 0 8
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
8 HASH UNIQUE (cr=44244 pr=40358 pw=0 time=21831482 us)
10000000 HASH JOIN (cr=44244 pr=40358 pw=0 time=20004628 us)
9 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=120 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=40358 pw=0 time=109 us)
추출하고자 하는 대상은 DEPT 테이블의 데이터임에도 불구하고
EMP 테이블과 조인을 시도하였다.
결국 두 테이블의 관계가 1 : M 이므로 불필요하게 EMP 테이블을
모두 액세스하고 DISTINCT로 중복 제거를 하였다.
II. 10046 Trace
추출하고자 하는 대상 테이블이 어디인가?
사례연구
SELECT D.*
FROM DEPT D
WHERE EXISTS (SELECT 1
FROM EMP E
WHERE E.DEPTNO = D.DEPTNO);
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
1. 성능 관점에서 효율적인 SQL 구성
추출하고자 하는
대상 테이블만을
FROM절에 위치시키자
67 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Fetch 2 0.000 0.042 7 24 0 8
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 4 0.000 0.046 7 24 0 8
Misses in library cache during parse: 1
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
8 NESTED LOOPS SEMI (cr=24 pr=7 pw=0 time=7432 us)
9 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=263 us)
8 INDEX RANGE SCAN EMP_N1 (cr=20 pr=7 pw=0 time=42135 us)(Object ID 6652496)
추출하고자 하는 대상만을 FROM절에 놓고 나머지는 체크만 하기
위해 EXISTS절에 위치시켰으며 이로 인해 수행속도가 대폭 감소되
었다.
II. 10046 Trace
OLTP 화면에서 부분범위처리를 하려면?
사례연구
2. 부분범위처리 튜닝 방법
사업부 이름 조회
사업부 이름 사업부 번호 입사일자 업무팀 이름
68 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
15 ∨
rows
II. 10046 Trace
SQL Trace 확인
사례연구
SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
Trace를 확인한 결과 901건이 추출되었다.
이 중 화면상에 설계된 15건만 부분범위 처리하여
보여주고자 한다.
2. 부분범위처리 튜닝 방법
69 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND D.DNAME = :B1;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.001 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 92 43.910 45.473 6989 44244 0 901
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 94 43.910 45.477 6989 44244 0 901
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
901 HASH JOIN (cr=44244 pr=6989 pw=0 time=44110198 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=126 us)
1000007 VIEW (cr=44241 pr=6989 pw=0 time=46107766 us)
1000007 HASH GROUP BY (cr=44241 pr=6989 pw=0 time=45107756 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=6989 pw=0 time=10000130 us)
II. 10046 Trace
ROWNUM 사용 . Trace 내용
사례연구
SELECT *
FROM (SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
최종 SQL에 ROWNUM을 넣은 뒤 인라인 뷰로 만
든 다음 밖에서 화면 설계된 로우수 만큼 추출하는
조건을 준다.
부분범위 처리 조건
2. 부분범위처리 튜닝 방법
. 실행계획에서 모든 조인은 NL 조인이 되어야
한다. 만약 HASH JOIN이 하나라도 있으면 부
분범위처리가 안된다.
. NL 조인이 되더라도 View Merging이 되어야 한
다.
70 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE CNT <= 15;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 3 43.170 42.211 0 44244 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 43.170 42.218 0 44244 0 15
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 VIEW (cr=44244 pr=0 pw=0 time=40881287 us)
901 COUNT (cr=44244 pr=0 pw=0 time=40883966 us)
901 HASH JOIN (cr=44244 pr=0 pw=0 time=40883056 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=131 us)
1000007 VIEW (cr=44241 pr=0 pw=0 time=41880601 us)
1000007 HASH GROUP BY (cr=44241 pr=0 pw=0 time=41880596 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=0 pw=0 time=114 us)
ROWNUM
적용 HASH JOIN이 적용되어
부분범위 처리를 하지 못하고
EMP 테이블을 모두 액세스함
II. 10046 Trace 사례연구
SELECT *
FROM (SELECT D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
DEPT D
2. 부분범위처리 튜닝 방법
ROWNUM 사용 . DBMS_XPLAN.DISPLAY 내용
71 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE CNT <= 15;
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 706K| 40M| | 40769 (4)| 00:08:10 |
|* 1 | VIEW | | 706K| 40M| | 40769 (4)| 00:08:10 |
| 2 | COUNT | | | | | | |
|* 3 | HASH JOIN | | 706K| 15M| | 40769 (4)| 00:08:10 |
|* 4 | TABLE ACCESS FULL | DEPT | 1 | 11 | | 3 (0)| 00:00:01 |
| 5 | VIEW | | 3534K| 40M| | 40731 (4)| 00:08:09 |
| 6 | HASH GROUP BY | | 3534K| 43M| 311M| 40731 (4)| 00:08:09 |
| 7 | TABLE ACCESS FULL| EMP | 10M| 124M| | 12240 (3)| 00:02:27 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CNT"<=15)
3 - access("EMP_V"."DEPTNO"="D"."DEPTNO")
4 - filter("D"."DNAME"=:B1)
II. 10046 Trace
힌트 사용 . Trace 내용
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D) USE_NL(D EMP_V) PUSH_PRED(EMP_V) INDEX(EMP_V.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
2. 부분범위처리 튜닝 방법
NL 조인이 되었음에도 불구하고
EMP_V 뷰 안에 GROUP BY가
있어서 View Merging이 안됨
72 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1) WHERE CNT <= 15;
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.002 0 0 0 0
Execute 1 0.000 0.004 0 0 0 0
Fetch 3 32.600 31.880 0 44245 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 32.600 31.886 0 44245 0 15
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 VIEW (cr=44245 pr=0 pw=0 time=30636573 us)
901 COUNT (cr=44245 pr=0 pw=0 time=30639256 us)
901 NESTED LOOPS (cr=44245 pr=0 pw=0 time=30638349 us)
1 TABLE ACCESS FULL DEPT (cr=4 pr=0 pw=0 time=204 us)
901 VIEW (cr=44241 pr=0 pw=0 time=30637328 us)
1000007 SORT GROUP BY (cr=44241 pr=0 pw=0 time=31636297 us)
10000000 TABLE ACCESS FULL EMP (cr=44241 pr=0 pw=0 time=113 us)
Nested Loop 확인
II. 10046 Trace
힌트 사용 . DBMS_XPLAN.DISPLAY 내용
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D) USE_NL(D EMP_V) PUSH_PRED(EMP_V) INDEX(EMP_V.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB,
ROWNUM CNT
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
MIN(E.JOB) MIN_JOB
FROM EMP E
GROUP BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')) EMP_V,
2. 부분범위처리 튜닝 방법
73 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1) WHERE CNT <= 15;
---------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
---------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 706K| 40M| | 40734 (4)| 00:08:09 |
|* 1 | VIEW | | 706K| 40M| | 40734 (4)| 00:08:09 |
| 2 | COUNT | | | | | | |
| 3 | NESTED LOOPS | | 706K| 15M| | 40734 (4)| 00:08:09 |
|* 4 | TABLE ACCESS FULL | DEPT | 1 | 11 | | 3 (0)| 00:00:01 |
|* 5 | VIEW | | 706K| 8284K| | 40731 (4)| 00:08:09 |
| 6 | SORT GROUP BY | | 3534K| 43M| 311M| 40731 (4)| 00:08:09 |
| 7 | TABLE ACCESS FULL| EMP | 10M| 124M| | 12240 (3)| 00:02:27 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter("CNT"<=15)
4 - filter("D"."DNAME"=:B1)
5 - filter("EMP_V"."DEPTNO"="D"."DEPTNO")
II. 10046 Trace
그룹함수를 분석함수로 대체
사례연구
SELECT *
FROM (SELECT /*+ LEADING(D)
USE_NL(D EMP_V)
PUSH_PRED(EMP_V)
INDEX(EMP_V.INLINE_EMP.E EMP_N1) */
D.DNAME,
EMP_V.DEPTNO,
EMP_V.HIREDATE,
EMP_V.MIN_JOB
2. 부분범위처리 튜닝 방법
74 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM (SELECT INLINE_EMP.DEPTNO,
INLINE_EMP.HIREDATE,
INLINE_EMP.MIN_JOB
FROM (SELECT E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD') HIREDATE,
E.JOB MIN_JOB,
ROW_NUMBER() OVER(PARTITION BY E.DEPTNO,
TO_CHAR(E.HIREDATE, 'YYYYMMDD')
ORDER BY E.JOB) GUBN
FROM EMP E) INLINE_EMP
WHERE INLINE_EMP.GUBN = 1) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DNAME = :B1)
WHERE ROWNUM <= 15;
분석함수를 사용하여
View Merging이 되도록
유도함
II. 10046 Trace
그룹함수를 분석함수로 대체 . DBMS_XPLAN.DISPLAY 내용
사례연구
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Rows | Bytes |TempSpc| Cost (%CPU)| Time |
--------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 15 | 765 | | 4 (0)| 00:00:01 |
|* 1 | COUNT STOPKEY | | | | | | |
| 2 | NESTED LOOPS | | 1111K| 54M| | 4 (0)| 00:00:01 |
|* 3 | TABLE ACCESS FULL | DEPT | 1 | 14 | | 3 (0)| 00:00:01 |
|* 4 | VIEW PUSHED PREDICATE | | 3 | 111 | | 1 (0)| 00:00:01 |
|* 5 | WINDOW SORT PUSHED RANK | | 2001K| 24M| 91M| 26239 (2)| 00:05:15 |
2. 부분범위처리 튜닝 방법
75 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 2001K| 24M| | 16592 (1)| 00:03:20 |
|* 7 | INDEX RANGE SCAN | EMP_N1 | 2018K| | | 3986 (2)| 00:00:48 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(ROWNUM<=15)
3 - filter("D"."DNAME"=:B1)
4 - filter("INLINE_EMP"."GUBN"=1)
5 - filter(ROW_NUMBER() OVER ( PARTITION BY
"E"."DEPTNO",TO_CHAR(INTERNAL_FUNCTION("E"."HIREDATE"),'YYYYMMDD')
ORDER BY "E"."JOB")<=1)
7 - access("E"."DEPTNO"="D"."DEPTNO") 조인 조건이 뷰 안으로
침투가 된 것이 확인됨
II. 10046 Trace
그룹함수를 분석함수로 대체 . Trace 내용
사례연구
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.010 0 0 0 0
Fetch 3 0.060 0.055 18 59 0 15
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 5 0.060 0.068 18 59 0 15
Misses in library cache during parse: 1
2. 부분범위처리 튜닝 방법
76 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Optimizer goal: ALL_ROWS
Parsing user: APPS (ID=44)
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
15 COUNT STOPKEY (cr=59 pr=18 pw=0 time=53933 us)
15 NESTED LOOPS (cr=59 pr=18 pw=0 time=53924 us)
1 TABLE ACCESS FULL DEPT (cr=3 pr=0 pw=0 time=85 us)
15 VIEW PUSHED PREDICATE (cr=56 pr=18 pw=0 time=53834 us)
132 WINDOW SORT PUSHED RANK (cr=56 pr=18 pw=0 time=54082 us)
9000 TABLE ACCESS BY INDEX ROWID EMP (cr=56 pr=18 pw=0 time=18068 us)
9000 INDEX RANGE SCAN EMP_N1 (cr=21 pr=18 pw=0 time=9053 us)(Object ID 6720703)
View Merging이 되어
PUSHED PREDICATE
실행계획이 나타남
II. 10046 Trace Q & A
77 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
III. DBMS_XPLAN.DISPLAY_CURSOR
III. DBMS_XPLAN.DISPLAY_CURSOR
INTRODUCTION
78 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR?
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
79 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY
10046 Trace
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
예측정보이므로 정확한 튜닝결과를 알 수 없다.
실측정보이므로 강력하지만 Trc 파일을 얻으려면 서버에 접근해야 함
하지만 일반 사이트에서는 개발자들에게 서버 접근 권한을 주지 않음
80 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR
그러므로 개발자들이 Trc 파일을 이용하기에는 버거운 상태임
그럼 개발자들는 튜닝을 할 수 없는 것인가?
해결방법은 DBMS_XPLAN.DISPLAY_CURSOR
DISPLAY가 예측치를 보여주는 거라면 DISPLAY_CURSOR는 실측치
를 보여줌
DBMS_XPLAN.DISPLAY_CURSOR
III. DBMS_XPLAN.DISPLAY_CURSOR
단일 SQL문에 대해 실제 수행된 실행계획을 보여주는 Function
FUNCTION DISPLAY_CURSOR(SQL_ID VARCHAR2 DEFAULT NULL,
CURSOR_CHILD_NO INTEGER DEFAULT 0,
FORMAT VARCHAR2 DEFAULT 'TYPICAL')
Function Parameter
파라미터 설명
INTRODUCTION
81 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
파라미터 설명
TABLE_NAME
실제 수행된 SQL의 SQL_ID 값을 입력하면 해당 SQL의 실행계획을 볼 수 있다.
SQL_ID 값은 V$SQL, V$SQLAREA에서 확인할 수 있다.
SQL_ID 값을 명시하지 않으면 해당 세션의 마지막에 실행된 문장을 의미한다.
STATEMENT_ID
해당 SQL_ID의 CHILD NUMBER 값을 지정한다.
CURSOR_CHILD_NO 값을 명시하지 않으면 해당 SQL_ID의 첫번째 CURSOR_CHILD_NO 값을 가져온다.
FORMAT 저장된 PLAN을 어떤 Format으로 보여줄 지 결정하는 파라미터
FORMAT
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 FORMAT 내용
예측
내용
BASIC DBMS_XPLAN.DISPLAY 포멧과 같은 내용
TYPICAL DBMS_XPLAN.DISPLAY 포멧과 같은 내용
ALL DBMS_XPLAN.DISPLAY 포멧과 같은 내용
OUTLINE DBMS_XPLAN.DISPLAY 포멧과 같은 내용
ADVANCED DBMS_XPLAN.DISPLAY 포멧과 같은 내용
82 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
실측
내용
ALLSTATS
실제 액세스한 로우수와 수행시간 그리고 CR, PR, PW 정보를
보여준다.
수행횟수에 따라 누적된 값을 보여준다.
ALLSTATS LAST
실제 액세스한 로우수와 수행시간 그리고 CR, PR, PW 정보를
보여준다.
가장 최근에 수행된 값만 보여준다.
ADVANCED ALLSTATS
LAST
DBMS_XPLAN.DISPLAY_CURSOR에서 지원하는 모든 Format의
정보를 보여준다.
사용방법
PLAN_STATISTICS 정보는 다음의 조건 중 하나를 만족해야 기록됨
이 Package를 사용하기 위해서는 아래의 객체에 SELECT 권한이 있어야 함
V$SESSION
V$SQL_PLAN
V$SQL(optional)
V$SQL_PLAN_STATISTICS_ALL
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
83 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
'STATISTICS_LEVEL' Parameter 값을 ALL로 변경한 경우
'_ROWSOURCE_EXECUTION_STATISTICS' Parameter 값을 TRUE로 변경한 경우
GATHER_PLAN_STATISTICS HINT를 사용할 때, 10g부터 지원
WINDOW 환경에서 SQL*PLUS를 사용할 때
이 경우에 DBMS_XPLAN.DISPLAY_CURSOR 정보를 보려면 다음의 구문 사용해야
SET SERVEROUTPUT OFF;
Runtime Execution Plan 확인방법
이 펑션은 이미 수행된 SQL의 PLAN을 확인할 수 있는 장점이 있다.
이미 수행된 SQL은 V$SQL을 조회하여 확인할 수 있다
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
Sample
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
1. SQL 실행
84 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
;
no rows selected
SELECT SUBSTR(SQL_TEXT, 1, 30) SQL_TEXT,
SQL_ID,
CHILD_NUMBER
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT * FROM EMP E%'
;
SQL_TEXT SQL_ID CHILD_NUMBER
------------------------------ ------------- ------------
SELECT * FROM EMP E WHERE E ak7vxhj055996 0
2. V$SQL에서 SQL_ID 확인
Runtime Execution Plan 확인방법
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('ak7vxhj055996', 0, 'ALLSTATS LAST'));
-------------------------------------------------------
| Id | Operation | Name | E-Rows |
-------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 |
-------------------------------------------------------
Predicate Information (identified by operation id):
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
3. DBMS_XPLAN.DISPLAY_CURSOR 조회
85 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
---------------------------------------------------
1 - filter("E"."DEPTNO"=10)
2 - access("E"."EMPNO"=9999999)
Note
-----
- Warning: basic plan statistics not available. These are only collected when:
* hint 'gather_plan_statistics' is used for the statement or
* parameter 'statistics_level' is set to 'ALL', at session or system level
수행한 SQL이 다음의 조건을 충족하지 않았기 때문에 기록이 안됨
'STATISTICS_LEVEL' Parameter 값을 ALL로 변경한 경우
'_ROWSOURCE_EXECUTION_STATISTICS' Parameter 값을 TRUE로 변경한 경우
GATHER_PLAN_STATISTICS HINT를 사용할 때, 10g부터 지원
Runtime Execution Plan 확인방법
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT *
FROM EMP E
WHERE E.EMPNO = 9999999
AND E.DEPTNO = 10
;
no rows selected
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
4. STATISTICS_LEVEL 파라미터 값 변경 이후 추가 수행
세션 레벨의
파라미터 변경
86 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT SUBSTR(SQL_TEXT, 1, 30) SQL_TEXT,
SQL_ID,
CHILD_NUMBER
FROM V$SQL
WHERE SQL_TEXT LIKE 'SELECT * FROM EMP E%'
;
SQL_TEXT SQL_ID CHILD_NUMBER
------------------------------ ------------- ------------
SELECT * FROM EMP E WHERE E ak7vxhj055996 0
SELECT * FROM EMP E WHERE E ak7vxhj055996 1
동일한 SQL을 'STATISTICS_LEVEL' 값을 변경하여 수행하였기 때문에
CHILD_NUMBER 값으로 구분
CHILD_NUMBER
추가 확인
Runtime Execution Plan 확인방법
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR('ak7vxhj055996', 1, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------
| Id | Operation | Name | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 0 |00:00:00.01 | 4 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 | 1 |00:00:00.01 | 3 |
---------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
5. DBMS_XPLAN.DISPLAY_CURSOR 다시 조회
추가
정보
-------------------------------------------------------
실제
수행한
결과
87 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| Id | Operation | Name | E-Rows |
-------------------------------------------------------
|* 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 |
|* 2 | INDEX UNIQUE SCAN | EMP_U1 | 1 |
-------------------------------------------------------
예측
결과
예측 실행계획과 실제 실행계획 비교
A-Rows, A-Time, Buffer 추가 정보 보여줌
E : Estimate, A : Actual
ALLSTATS Format
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 항목 설명
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Starts 각 Operation을 수행한 회수(만약 NL Join이라면 Looping한 회수)
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
88 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
PLAN 정보 E-Rows 각 Operation에서 예측한 로우수
A-Rows 각 Operation에서 실제 액세스한 로우수
A-Time 각 Operation에서 실제 수행된 시간(단위 : 초)
Buffer 각 Operation에서 실제 읽은 Logical Block
Read 각 Operation에서 실제 읽은 Physical Block
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보
이 Format은 Starts, A-Rows, Buffer의 출력값을 누적하여 보여준다.
ALLSTATS Format
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ USE_NL(E D) */
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO IN (10, 20, 30)
;
Sample
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
89 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS'));
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 999 |00:00:00.26 | 156 | 10 |
| 2 | NESTED LOOPS | | 1 | 2701K| 1003 |00:00:07.22 | 86 | 6 |
| 3 | INLIST ITERATOR | | 1 | | 3 |00:00:00.03 | 9 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 3 |00:00:00.03 | 9 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | 3 |00:00:00.02 | 6 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| 999 |00:00:00.21 | 77 | 4 |
-------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(("D"."DEPTNO"=10 OR "D"."DEPTNO"=20 OR "D"."DEPTNO"=30))
6 - access("E"."DEPTNO"="D"."DEPTNO")
filter(("E"."DEPTNO"=10 OR "E"."DEPTNO"=20 OR "E"."DEPTNO"=30))
ALLSTATS Format
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 999 |00:00:00.26 | 156 | 10 |
| 2 | NESTED LOOPS | | 1 | 2701K| 1003 |00:00:07.22 | 86 | 6 |
| 3 | INLIST ITERATOR | | 1 | | 3 |00:00:00.03 | 9 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 3 |00:00:00.03 | 9 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | 3 |00:00:00.02 | 6 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| 999 |00:00:00.21 | 77 | 4 |
-------------------------------------------------------------------------------------------------------------
Sample
1회
수행
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
90 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
-------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 2 | 900K| 1998 |00:00:00.28 | 312 | 10 |
| 2 | NESTED LOOPS | | 2 | 2701K| 2006 |00:00:07.25 | 172 | 6 |
| 3 | INLIST ITERATOR | | 2 | | 6 |00:00:00.03 | 18 | 2 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 6 | 3 | 6 |00:00:00.03 | 18 | 2 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 6 | 3 | 6 |00:00:00.02 | 12 | 1 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 6 | 906K| 1998 |00:00:00.22 | 154 | 4 |
-------------------------------------------------------------------------------------------------------------
2회
수행
누적
정보
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
구분 항목 설명
ID 각 Operation ID
Operation 로우 단위의 액세스 정보
Name 액세스 하는 Object의 정보
Starts 각 Operation을 수행한 회수(만약 NL Join이라면 Looping한 회수)
ALLSTATS LAST Format ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
91 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
PLAN 정보 E-Rows 각 Operation에서 예측한 로우수
A-Rows 각 Operation에서 실제 액세스한 로우수
A-Time 각 Operation에서 실제 수행된 시간(단위 : 초)
Buffer 각 Operation에서 실제 읽은 Logical Block
Read 각 Operation에서 실제 읽은 Physical Block
추가 정보
Predicate
Information
SQL에서 WHERE절에 사용되는 조건들이 각 Operation에 적용되는 정보
LAST Format은 Starts, A-Rows, Buffer의 출력값을 최근 수행한 결과만 보여준다.
ADVANCED ALLSTATS LAST Format
ADVANCED ALLSTATS LAST Format은
DBMS_XPLAN Package에서 제공하는 모든 Format의 결정판.
LAST이므로 가장 최근에 수행된 결과만 출력
Sample
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT /*+ USE_NL(E D) */
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
92 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
*
FROM EMP E,
DEPT D
WHERE E.DEPTNO = D.DEPTNO
AND D.DEPTNO IN (10, 20, 30)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
-----------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows | A-Time | Buffers |
-----------------------------------------------------------------------------------------------------------------------------------
| 1 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 900K| 22M| 9673 (1)| 00:01:57 | 999 |00:00:00.02 | 156 |
| 2 | NESTED LOOPS | | 1 | 2701K| 113M| 21467 (2)| 00:04:18 | 1003 |00:00:00.01 | 86 |
| 3 | INLIST ITERATOR | | 1 | | | | | 3 |00:00:00.01 | 9 |
| 4 | TABLE ACCESS BY INDEX ROWID| DEPT | 3 | 3 | 54 | 2 (0)| 00:00:01 | 3 |00:00:00.01 | 9 |
|* 5 | INDEX RANGE SCAN | DEPT_U1 | 3 | 3 | | 1 (0)| 00:00:01 | 3 |00:00:00.01 | 6 |
|* 6 | INDEX RANGE SCAN | EMP_N1 | 3 | 906K| | 4008 (2)| 00:00:49 | 999 |00:00:00.01 | 77 |
-----------------------------------------------------------------------------------------------------------------------------------
Sample
ADVANCED ALLSTATS LAST Format
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1 / E@SEL$1
4 - SEL$1 / D@SEL$1
5 - SEL$1 / D@SEL$1
6 - SEL$1 / E@SEL$1
Outline Data
-------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
93 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_optim_peek_user_binds' 'false')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
INDEX_RS_ASC(@"SEL$1" "D"@"SEL$1" ("DEPT"."DEPTNO"))
INDEX(@"SEL$1" "E"@"SEL$1" ("EMP"."DEPTNO"))
LEADING(@"SEL$1" "D"@"SEL$1" "E"@"SEL$1")
USE_NL(@"SEL$1" "E"@"SEL$1")
END_OUTLINE_DATA
*/
Sample
ADVANCED ALLSTATS LAST Format
Predicate Information (identified by operation id):
---------------------------------------------------
5 - access(("D"."DEPTNO"=10 OR "D"."DEPTNO"=20 OR "D"."DEPTNO"=30))
6 - access("E"."DEPTNO"="D"."DEPTNO")
filter(("E"."DEPTNO"=10 OR "E"."DEPTNO"=20 OR "E"."DEPTNO"=30))
Column Projection Information (identified by operation id):
-----------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
ALLSTATS
ALLSTATS LAST
ADVANCED ALLSTATS LAST
94 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1 - "E"."EMPNO"[NUMBER,22], "E"."EMPNO_VARCHAR"[VARCHAR2,40], "E"."JOB"[VARCHAR2,3], "E"."HIREDATE"[DATE,7],
"E"."DEPTNO"[NUMBER,22]
2 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45], "E".ROWID[ROWID,10],
"E"."DEPTNO"[NUMBER,22]
3 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45]
4 - "D"."DEPTNO"[NUMBER,22], "D"."DNAME"[VARCHAR2,46], "D"."LOC"[VARCHAR2,45]
5 - "D".ROWID[ROWID,10], "D"."DEPTNO"[NUMBER,22]
6 - "E".ROWID[ROWID,10], "E"."DEPTNO"[NUMBER,22]
10046 Trace vs DBMS_XPLAN.DISPLAY_CURSOR 비교
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SELECT *
FROM EMP E
WHERE TRIM(E.EMPNO) = 9999999
AND E.DEPTNO = 30
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
CURSOR : A-Rows
Trace : Rows
CURSOR : A-Time
Trace : time
CURSOR : Buffers
Trace : cr
CURSOR : Reads
Trace : pr
95 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
|* 1 | TABLE ACCESS FULL| EMP | 1 | 16659 | 0 |00:00:05.62 | 33299 | 33083 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("E"."DEPTNO"=30 AND TO_NUMBER(TRIM(TO_CHAR("E"."EMPNO")))=9999999))
Call Count CPU Time Elapsed Time Disk Query Current Rows
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Parse 1 0.000 0.003 0 0 0 0
Execute 1 0.000 0.000 0 0 0 0
Fetch 1 2.680 5.551 33082 33299 0 0
------- ------ -------- ------------ ---------- ---------- ---------- ----------
Total 3 2.680 5.554 33082 33299 0 0
Rows Row Source Operation
------- ---------------------------------------------------
0 STATEMENT
0 TABLE ACCESS FULL EMP (cr=33299 pr=33082 pw=0 time=5551325 us)
DISPLAY vs 10046 Trace vs DISPLAY_CURSOR 비교
전체 비교
항목
DBMS_XPLAN
DISPLAY
10046 Trace
DBMS_XPLAN
DISPLAY_CURSOR
수행결과 예측 실측 실측
SQL 수행 1개 1개 이상 1개
III. DBMS_XPLAN.DISPLAY_CURSOR INTRODUCTION
96 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Function 수행정보 X O X
단계별
통계치
X O X
PLAN 정보 O O O
추가정보 O X O
Predicate Information
Query Block
Column Projection Information
Outline Data
Parse
Execute
Fetch
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
97 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
1. 데이터타입 불일치일 경우
튜닝 전
사례연구
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = 111;
III. DBMS_XPLAN.DISPLAY_CURSOR
SET SERVEROUTPUT OFF
SET LINESIZE 2000
ALTER SESSION SET STATISTICS_LEVEL = ALL;
98 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS FULL| EMP | 1 | 1 | 1 |00:00:13.92 | 44242 | 43323 |
---------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_NUMBER("E"."EMPNO_VARCHAR")=111)
1. 데이터타입 불일치일 경우
튜닝 후
사례연구
SELECT *
FROM EMP E
WHERE E.EMPNO_VARCHAR = '111';
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR
99 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| 1 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 1 |00:00:00.01 | 5 | 3 |
|* 2 | INDEX RANGE SCAN | EMP_N3 | 1 | 1 | 1 |00:00:00.01 | 4 | 2 |
---------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("E"."EMPNO_VARCHAR"='111')
2. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
EXEC :B1 := '20090101';
EXEC :B2 := '20090131';
튜닝 전
SELECT *
FROM (SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
100 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
FROM EMP) EMP_V
WHERE EMP_V.HIREDATE BETWEEN :B1
AND :B2;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
----------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 300 |00:00:29.34 | 44261 | 43950 |
|* 2 | TABLE ACCESS FULL| EMP | 1 | 24979 | 300 |00:00:29.34 | 44261 | 43950 |
----------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(:B1<=:B2)
2 - filter((TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')>=:B1 AND
TO_CHAR(INTERNAL_FUNCTION("HIREDATE"),'YYYYMMDD')<=:B2))
2. 뷰 안의 조인(또는 조건)컬럼이 가공되어 있는 경우
EXEC :B1 := '20090101 00:00:00';
EXEC :B2 := '20090131 23:59:59';
튜닝 후
SELECT EMPNO,
JOB,
TO_CHAR(HIREDATE, 'YYYYMMDD') HIREDATE,
DEPTNO
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
101 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
WHERE EMP_V.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD HH24:MI:SS')
AND TO_DATE(:B2, 'YYYYMMDD HH24:MI:SS');
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 310 |00:00:00.01 | 49 | 2 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 24979 | 310 |00:00:00.01 | 49 | 2 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 310 |00:00:00.01 | 25 | 2 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(TO_DATE(:B1,'YYYYMMDD HH24:MI:SS')<=TO_DATE(:B2,'YYYYMMDD HH24:MI:SS'))
3 - access("HIREDATE">=TO_DATE(:B1,'YYYYMMDD HH24:MI:SS') AND
"HIREDATE"<=TO_DATE(:B2,'YYYYMMDD HH24:MI:SS'))
3. 뷰 안에 ROWNUM이 존재할 경우
ALTER SESSION SET STATISTICS_LEVEL = ALL;
튜닝 전
SELECT EMP_V.*
FROM (SELECT ROWNUM,
EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
102 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------
| 1 | NESTED LOOPS | | 1 | 9991K| 9 |00:00:25.47 | 44243 | 7482 |
|* 2 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 3 | VIEW | | 1 | 9991K| 9 |00:00:25.47 | 44242 | 7482 |
| 4 | COUNT | | 1 | | 10M|00:00:10.00 | 44242 | 7482 |
| 5 | TABLE ACCESS FULL| EMP | 1 | 9991K| 10M|00:00:10.00 | 44242 | 7482 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - access("D"."DEPTNO"=10)
3 - filter("EMP_V"."DEPTNO"=10)
3. 뷰 안에 ROWNUM이 존재할 경우
SELECT ROWNUM,
EMP_V.*
FROM (SELECT EMPNO,
JOB,
HIREDATE,
DEPTNO
FROM EMP) EMP_V,
DEPT D
WHERE EMP_V.DEPTNO = D.DEPTNO
AND D.DEPTNO = 10;
튜닝 후
III. DBMS_XPLAN.DISPLAY_CURSOR 사례연구
103 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
---------------------------------------------------------------------------------------------------
| 1 | COUNT | | 1 | | 9 |00:00:00.01 | 7 |
| 2 | NESTED LOOPS | | 1 | 1 | 9 |00:00:00.01 | 7 |
|* 3 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 |
| 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 1 | 9 |00:00:00.01 | 6 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 1 | 1 | 9 |00:00:00.01 | 4 |
---------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("D"."DEPTNO"=10)
5 - access("DEPTNO"=10)
4. OR 조건이 사용될 경우
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
VAR B1 NUMBER;
VAR B2 VARCHAR2(100);
VAR B3 VARCHAR2(100);
튜닝 전
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
104 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXEC :B1 := 10;
EXEC :B2 := '20090401';
EXEC :B3 := '20090402';
SELECT *
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
4. OR 조건이 사용될 경우
SELECT *
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
튜닝 전
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
------------------------------------------------------------------------------------
105 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
------------------------------------------------------------------------------------
|* 1 | TABLE ACCESS FULL| EMP | 1 | 2021K| 29 |00:00:08.84 | 44242 |
------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
1 - filter(("E"."DEPTNO"=:B1 OR ("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')
AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))))
4. OR 조건이 사용될 경우
SElECT *
FROM EMP E
WHERE E.DEPTNO = :B1
AND :B1 IS NOT NULL
1차 튜닝 . UNION ALL 분리
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SElECT *
FROM EMP E
WHERE E.HIREDATE BETWEEN :B2
AND :B3
AND :B1 IS NULL;
UNION ALL
106 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
--------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers |
--------------------------------------------------------------------------------------------------
| 1 | UNION-ALL | | 1 | | 9 |00:00:07.85 | 44242 |
|* 2 | FILTER | | 1 | | 9 |00:00:07.85 | 44242 |
|* 3 | TABLE ACCESS FULL | EMP | 1 | 2506K| 9 |00:00:07.85 | 44242 |
|* 4 | FILTER | | 1 | | 0 |00:00:00.01 | 0 |
| 5 | TABLE ACCESS BY INDEX ROWID| EMP | 0 | 25065 | 0 |00:00:00.01 | 0 |
|* 6 | INDEX RANGE SCAN | EMP_N2 | 0 | 45525 | 0 |00:00:00.01 | 0 |
--------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:B1 IS NOT NULL)
3 - filter("E"."DEPTNO"=:B1)
4 - filter((TO_DATE(:B2,'YYYYMMDD')<=TO_DATE(:B3,'YYYYMMDD') AND :B1 IS NULL))
6 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND
"E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4. OR 조건이 사용될 경우
SElECT /*+ INDEX(E EMP_N1) */
*
FROM EMP E
WHERE E.DEPTNO = :B1
AND :B1 IS NOT NULL
UNION ALL
SElECT *
FROM EMP E
WHERE E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
AND :B1 IS NULL;
1차 튜닝 . UNION ALL 분리 > 힌트 사용
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
107 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
-----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
-----------------------------------------------------------------------------------------------------------
| 1 | UNION-ALL | | 1 | | 9 |00:00:00.03 | 6 | 3 |
|* 2 | FILTER | | 1 | | 9 |00:00:00.03 | 6 | 3 |
| 3 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 2506K| 9 |00:00:00.03 | 6 | 3 |
|* 4 | INDEX RANGE SCAN | EMP_N1 | 1 | 2506K| 9 |00:00:00.02 | 4 | 2 |
|* 5 | FILTER | | 1 | | 0 |00:00:00.01 | 0 | 0 |
| 6 | TABLE ACCESS BY INDEX ROWID| EMP | 0 | 25065 | 0 |00:00:00.01 | 0 | 0 |
|* 7 | INDEX RANGE SCAN | EMP_N2 | 0 | 45525 | 0 |00:00:00.01 | 0 | 0 |
-----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(:B1 IS NOT NULL)
4 - access("E"."DEPTNO"=:B1)
5 - filter((TO_DATE(:B2,'YYYYMMDD')<=TO_DATE(:B3,'YYYYMMDD') AND :B1 IS NULL))
7 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용
108 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:01.96 | 44250 | 2 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 25065 | 20 |00:00:00.03 | 9 | 2 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 45525 | 20 |00:00:00.03 | 5 | 2 |
|* 4 | TABLE ACCESS FULL | EMP | 1 | 2500K| 9 |00:00:07.93 | 44241 | 0 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4 - filter(("E"."DEPTNO"=:B1 AND (LNNVL("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')) OR
LNNVL("E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD')))))
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
)
;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 확인
Query Block Name 사용 방법
@ + Query Block Name Object Alias
Ex) SEL$1_2 / E@SEL$1_2
@SEL$1_2 E@SEL$1_2
109 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:05.30 | 44250 | 4174 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 25065 | 20 |00:00:00.01 | 9 | 0 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 45525 | 20 |00:00:00.01 | 5 | 0 |
|* 4 | TABLE ACCESS FULL | EMP | 1 | 2500K| 9 |00:00:05.30 | 44241 | 4174 |
----------------------------------------------------------------------------------------------------------
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1
2 - SEL$1_1 / E@SEL$1
3 - SEL$1_1 / E@SEL$1
4 - SEL$1_2 / E@SEL$1_2
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 확인
Outline Data
-------------
110 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
/*+
BEGIN_OUTLINE_DATA
IGNORE_OPTIM_EMBEDDED_HINTS
OPTIMIZER_FEATURES_ENABLE('10.2.0.3')
OPT_PARAM('_b_tree_bitmap_plans' 'false')
OPT_PARAM('_fast_full_scan_enabled' 'false')
OPT_PARAM('_optim_peek_user_binds' 'false')
ALL_ROWS
OUTLINE_LEAF(@"SEL$1")
OUTLINE_LEAF(@"SEL$1_1")
USE_CONCAT(@"SEL$1" 8)
OUTLINE_LEAF(@"SEL$1_2")
OUTLINE(@"SEL$1")
INDEX_RS_ASC(@"SEL$1_1" "E"@"SEL$1" ("EMP"."HIREDATE"))
FULL(@"SEL$1_2" "E"@"SEL$1_2")
END_OUTLINE_DATA
*/
4. OR 조건이 사용될 경우
SElECT /*+ USE_CONCAT
INDEX(@SEL$1_2 E@SEL$1_2 EMP_N1) */
*
FROM EMP E
WHERE (E.DEPTNO = :B1
OR
E.HIREDATE BETWEEN TO_DATE(:B2, 'YYYYMMDD')
AND TO_DATE(:B3, 'YYYYMMDD')
);
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . USE_CONCAT 힌트 사용 > Query Block Name Hint 사용
111 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
----------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------------
| 1 | CONCATENATION | | 1 | | 29 |00:00:00.01 | 13 | 8 |
| 2 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 24979 | 20 |00:00:00.01 | 9 | 5 |
|* 3 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.01 | 5 | 3 |
|* 4 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 2491K| 9 |00:00:00.01 | 4 | 3 |
|* 5 | INDEX RANGE SCAN | EMP_N1 | 1 | 2497K| 9 |00:00:00.01 | 3 | 3 |
----------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
3 - access("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD') AND "E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))
4 - filter((LNNVL("E"."HIREDATE">=TO_DATE(:B2,'YYYYMMDD')) OR
LNNVL("E"."HIREDATE"<=TO_DATE(:B3,'YYYYMMDD'))))
5 - access("E"."DEPTNO"=:B1)
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
ALTER SESSION SET STATISTICS_LEVEL = ALL ;
SET SERVEROUTPUT OFF;
SET LINESIZE 2000;
VAR B1 VARCHAR2(100);
VAR B2 VARCHAR2(100);
VAR B3 NUMBER;
EXEC :B1 := '00010101';
EXEC :B2 := '00010102';
112 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
EXEC :B3 := 10;
SELECT *
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ADVANCED ALLSTATS LAST'));
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SELECT *
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
113 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 2 | MERGE JOIN SEMI | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 3 | NESTED LOOPS | | 1 | 9 |00:00:08.72 | 44243 | 43938 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 5 | TABLE ACCESS FULL | EMP | 1 | 9 |00:00:08.72 | 44242 | 43938 |
|* 6 | SORT UNIQUE | | 9 | 9 |00:00:00.02 | 4 | 2 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 9 |00:00:00.02 | 4 | 2 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 20 |00:00:00.02 | 3 | 2 |
----------------------------------------------------------------------------------------------------
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
튜닝전 . 액세스 순서를 D E_2 E_1으로 유도하고자 함
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
----------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | A-Rows | A-Time | Buffers | Reads |
----------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 2 | MERGE JOIN SEMI | | 1 | 9 |00:00:08.74 | 44247 | 43940 |
| 3 | NESTED LOOPS | | 1 | 9 |00:00:08.72 | 44243 | 43938 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 |00:00:00.01 | 1 | 0 |
|* 5 | TABLE ACCESS FULL | EMP | 1 | 9 |00:00:08.72 | 44242 | 43938 |
|* 6 | SORT UNIQUE | | 9 | 9 |00:00:00.02 | 4 | 2 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 9 |00:00:00.02 | 4 | 2 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 20 |00:00:00.02 | 3 | 2 |
----------------------------------------------------------------------------------------------------
114 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Query Block Name / Object Alias (identified by operation id):
-------------------------------------------------------------
1 - SEL$1F949E82
4 - SEL$1F949E82 / D@SEL$2
5 - SEL$1F949E82 / E_1@SEL$2
7 - SEL$1F949E82 / E_2@SEL$3
8 - SEL$1F949E82 / E_2@SEL$3
Outline Data
-------------
/*+
INDEX(@"SEL$1F949E82" "D"@"SEL$2" ("DEPT"."DEPTNO"))
FULL(@"SEL$1F949E82" "E_1"@"SEL$2")
INDEX_RS_ASC(@"SEL$1F949E82" "E_2"@"SEL$3" ("EMP"."HIREDATE"))
LEADING(@"SEL$1F949E82" "D"@"SEL$2" "E_1"@"SEL$2" "E_2"@"SEL$3")
USE_NL(@"SEL$1F949E82" "E_1"@"SEL$2")
USE_MERGE(@"SEL$1F949E82" "E_2"@"SEL$3")
END_OUTLINE_DATA
*/
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
SELECT /*+ LEADING(@SEL$1F949E82 D@SEL$2 E_2@SEL$3 E_1@SEL$2) */
*
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
1차 튜닝 . Query Block Name을 이용하여 액세스 순서 조정
115 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
--------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
--------------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 9 |00:00:06.92 | 44247 | 43959 |
|* 2 | HASH JOIN | | 1 | 3899M| 9 |00:00:06.92 | 44247 | 43959 |
| 3 | NESTED LOOPS | | 1 | 6245 | 1 |00:00:00.05 | 5 | 3 |
|* 4 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
| 5 | SORT UNIQUE | | 1 | 6245 | 1 |00:00:00.05 | 4 | 3 |
|* 6 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 6245 | 9 |00:00:00.05 | 4 | 3 |
|* 7 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.05 | 3 | 3 |
|* 8 | TABLE ACCESS FULL | EMP | 1 | 2497K| 9 |00:00:06.87 | 44242 | 43956 |
--------------------------------------------------------------------------------------------------------------
5. View안의 서브쿼리 액세스 순서를 핸들링하는 경우
III. DBMS_XPLAN.DISPLAY_CURSOR Query Block Name을 이용한 사례 연구
2차 튜닝 . Query Block Name을 이용하여 인덱스 유도
SELECT /*+ LEADING(@SEL$1F949E82 D@SEL$2 E_2@SEL$3 E_1@SEL$2) USE_NL(@SEL$1F949E82 E_1@SEL$2) */
*
FROM (SELECT E_1.EMPNO,
E_1.JOB,
E_1.HIREDATE,
D.DEPTNO
FROM EMP E_1,
DEPT D
WHERE E_1.DEPTNO = D.DEPTNO
AND EXISTS (SELECT 1
FROM EMP E_2
WHERE E_2.DEPTNO = E_1.DEPTNO
116 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
AND E_2.HIREDATE BETWEEN TO_DATE(:B1, 'YYYYMMDD')
AND TO_DATE(:B2, 'YYYYMMDD')
)
) EMP_V
WHERE EMP_V.DEPTNO = :B3;
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY_CURSOR(NULL, NULL, 'ALLSTATS LAST'));
---------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
---------------------------------------------------------------------------------------------------------------
|* 1 | FILTER | | 1 | | 9 |00:00:00.01 | 11 | 3 |
| 2 | TABLE ACCESS BY INDEX ROWID | EMP | 1 | 624K| 9 |00:00:00.01 | 11 | 3 |
| 3 | NESTED LOOPS | | 1 | 3899M| 11 |00:00:00.01 | 9 | 3 |
| 4 | NESTED LOOPS | | 1 | 6245 | 1 |00:00:00.01 | 5 | 0 |
|* 5 | INDEX UNIQUE SCAN | DEPT_U1 | 1 | 1 | 1 |00:00:00.01 | 1 | 0 |
| 6 | SORT UNIQUE | | 1 | 6245 | 1 |00:00:00.01 | 4 | 0 |
|* 7 | TABLE ACCESS BY INDEX ROWID| EMP | 1 | 6245 | 9 |00:00:00.01 | 4 | 0 |
|* 8 | INDEX RANGE SCAN | EMP_N2 | 1 | 44962 | 20 |00:00:00.01 | 3 | 0 |
|* 9 | INDEX RANGE SCAN | EMP_N1 | 1 | 624K| 9 |00:00:00.01 | 4 | 3 |
---------------------------------------------------------------------------------------------------------------
III. DBMS_XPLAN.DISPLAY_CURSOR Q & A
117 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
Q & A
SQL 성능에 대처하는 방법
SQL 성능에 대처하는 방법
118 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
SQL 튜닝을 하고 싶은데 방법을 모르겠다!
SQL 튜닝을 하려면 고급 TOOL이 필요하다던데?
SQL 튜닝을 할 때 Trace를 이용하라던데?
Trace 읽는 권한이 없어서 볼 수가 없는데 이 경우에는?
SQL 성능에 대처하는 방법
119 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
DBMS_XPLAN.DISPLAY_CURSOR
Package
수고하셨습니다!!!
120 / DBMS_XPLAN과 10046 Trace를 이용한 SQL문 튜닝 oracleclub.com
피드 구독하기:
글 (Atom)