행위

"10046 event 트레이스"의 두 판 사이의 차이

DB CAFE

(= 10046 event 끄기)
 
(같은 사용자의 중간 판 29개는 보이지 않습니다)
1번째 줄: 1번째 줄:
 +
= 10046 Event =
 +
{{틀:설명상자
 +
|내용= 10046 Event는 SQL Tuning에 있어서 필요한 Tool인가?
 +
* Plan Statistics가 제공하지 못하는 중요한 정보를 제공해주기 때문
 +
: - 모든 SQL 문장의 Bind 변수 값을 추적할 수 있는 유일한 방법(Level 4)
 +
: - 모든 SQL 문장의 대기 현상(Wait)을 추적할 수 있는 유일한 방법(Level 8)
 +
}}
 +
== 10046 trace 실행 절차 ==
  
1. 10046 Event
+
=== 트레이스 식별자 지정 ===
+
<source lang=sql>
10046 Event는 SQL Tuning에 있어서 필수적인 Tool이다.
+
alter session set tracefile_identifier='test'; ==> orcl_ora_10024_test.trc 형태로 저장됨.
왜 Oracle10g에서도 Extended SQL Trace는 여전히 중요한 Tool인가?
+
</source>
Plan Statistics가 제공하지 못하는 중요한 정보를 제공해주기 때문이다.
+
 
- 모든 SQL 문장의 Bind 변수 값을 추적할 수 있는 유일한 방법(Level 4)
+
=== sql trace 시작 ===
- 모든 SQL 문장의 대기 현상(Wait)을 추적할 있는 유일한 방법(Level 8)
+
<source lang=sql>
+
ALTER SESSION SET SQL_TRACE = TRUE; -- level 1로 트레이스 활성화
Oracle10g의 Bind Capture 기능이 소개되면서 V$SQL_BIND_CAPTURE View를 통해 Bind 변수를 추적할 수 있는
+
</source>
방법이 생겼다. 하지만 Bind Capture는 본질적인 한계를 가지고 있다.
+
 
- 15분 간격으로 Capture를 수행. Capture주기는 _CURSOR_BIND_CAPTURE_INTERVAL Parameter값에 의해 결정.
+
=== event 를 level 12 로 설정 ===
(기본값 : 900(초)) 이 값을 줄임으로써 보다 공격적으로 Capture를 수행할 수 있다. 약간의 성능 저하를 감수해야 한다.
+
* level 12 = (level 4 + 8) , SQL trace 정보, 실행계획, 바인드 변수, 대기 이벤트 정보를 볼 있다.
아무리 Capture 주기를 줄인 다고 해도 모든 SQL 문장의 Bind 변수를 Capture 하는 것은 불가능하다.
+
 
- 하나의 SQL Cursor에 대해 정해진 메모리 크기만큼만 Bind Capture를 수행. 메모리 크기의 한계는
+
<source lang=sql>
_CURSOR_BIND_CAPTURE_AREA_SIZE Parameter 값에 의해 결정.(기본값 : 2000(Byte))
+
ALTER SESSION SET events '10046 trace name context forever, level 12';
+
</source>
많은 수의 Bind 변수를 사용하는 경우 V$SQL_BIND_CAPTURE View에 일부 Bind 변수 값이 누락되는 현상이 발생할 수
+
* 10046 = Query가 수행되는 이벤트. 즉 Query를 수행하는 "이벤트"를 의미.
있는데 이런 제약 조건 때문이다.
+
* trace name = Trace를 수행. 사건이 발생했을 때의 행위(Action)를 의미.  
- Oracle은 Select 문장과 Bind 변수가 Where 절에서 사용되었을 경우에만 Bind Capture를 수행.
+
* context forever, level 12 = 사건이 발생할 때마다 행위를 수행하되, 행위의 레벨을 12로
- V$SQL_BIND_CAPTURE View는 가장 “최근에” Capture된 Bind 변수 값을 보여준다.(Extended SQL Trace와 같은 역할은 불가)
+
 
+
=== sql 실행 ===
Oracle은 매우 많은 수의 View들을 통해 대기 현상을 Monitoring 할 수 있다.
+
<source lang=sql>
V$SESSION, V$SESSION_WAIT, V$SESSION_EVENT, V$SYSTEM_EVENT, V$ACTIVE_SESSION_HISTORY
+
select * from tb_xxx;
DBA_HIST_ACTIVE_SESS_HISTORY, V$EVENT_HISTOGRAM View 등이 대기 현상과 관련된 중요한 정보들을 제공한다.
+
</source>
  - 그 어떤 View도 10046 SQL Trace가 제공하는 것과 같은 포괄적인 추적 정보를 제공하지는 않는다.
+
 
+
 
2. 자동화에 대한 아이디어
+
==== sql trace 종료 ====
+
<source lang=sql>
10046 Event를 이용해 SQL Trace 수행을 자동화하는 방법이다.
+
ALTER SESSION SET SQL_TRACE = FALSE;
 +
</source>
 +
 
 +
 
 +
==== 10046 event 끄기 ====
 +
* 꺼주지 않으면, 수행하는 모든 SQL 에 대한 정보를 모은다.
 +
* level 0으로 지정해서 비활성화 하지 않는것에 유의할것.  
 +
<source lang=sql>
 +
ALTER SESSION SET events '10046 trace name context off';
 +
</source>
 +
 
 +
== 10046 디버깅 이벤트 레벨 ==
 +
{| class="wikitable"
 +
|-
 +
! 레벨 !! 설명
 +
|-
 +
| 0 || 디버깅 이벤트 비활성화
 +
|-
 +
| 1 ||
 +
# 디버깅 이벤트 활성화
 +
# DB 호출정보
 +
# SQL구문,응답시간,서비스시간
 +
# 처리 로우수,논리적 읽기 건수,물리적 읽기/쓰기 건수,실행계획
 +
# 그외 추가적인 정보 제공
 +
|-
 +
| 4 ||
 +
# 레벨1 제공정보 + 추가적인 바인드 변수 정보
 +
# 데이터타입,정밀도,변수 값
 +
|-
 +
| 8 ||
 +
# 레벨1 제공정보 + 추가적인 대기시간 정보
 +
# 처리중 발생한 대기에 대한 정보
 +
# 대기이벤트 이름,대기시간,대기 대상자원 식별 
 +
|-
 +
| 16 ||
 +
# 레벨1 제공정보 + 실행 계획의 STAT 정보
 +
|-
 +
| 32 ||
 +
# 레벨1 제공정보에서 실행계획에 관한 정보만 제외 (11g 이상)  
 +
|-
 +
| 64 ||
 +
# 레벨1 제공정보 + 첫번째 실행 후에도 실행 계획 정보 기록
 +
# 실행 계획 정보가 마지막으로 기록된 이후 특정 커서가 최소 1분이상 DB실행 시간이 소요되는경우
 +
# 레벨 16에서 모든 실행에 대한 정보를 기록하는 오버헤드가 클경우 사용 (11g 이상) 
 +
|}
 +
* 레벨을 조합하여서 사용할 수 있음.(레벨 1을 제외한 조합 가능)
 +
** 레벨 12(4 + 8) : 레벨 4 + 레벨 8을 동시에 활성화
 +
** 레벨 28(4 + 8 + 16) : 레벨 4 + 레벨 8 + 레벨 16 을 동시에 활성화
 +
** 레벨 68(4 + 64) : 레벨 4 + 레벨 64을 동시에 활성화
 +
 
 +
== 10046 Event Trace 자동화 ==
 +
* 10046 Event를 이용해 SQL Trace 수행을 자동화 스크립트
 +
<source lang=sql>
 
Connect …
 
Connect …
 
@trace on 10046 8
 
@trace on 10046 8
51번째 줄: 111번째 줄:
 
select
 
select
 
-- 아래 부분은 환경에 맞게 적절히 수정
 
-- 아래 부분은 환경에 맞게 적절히 수정
d.value ||’/’||p.value||’_ora_’||s.spid||’.trc’
+
d.value ||’/’||p.value||’_ora_’||s.spid||’.trc’as trace_file_name
as trace_file_name
+
from (select value from v$parameter where name = ’instance_name’) p
from (select value from v$parameter
+
  , (select value from v$parameter where name = ‘user_dump_dest’) d
where name = ’instance_name’) p,
+
  , (select spid from v$process where addr = (select paddr from v$session where sid = (select sid from v$mystat where rownum = 1))) s  
(select value from v$parameter
+
;
where name = ‘user_dump_dest’) d,
 
select spid from v$process
 
where addr = (select paddr from v$session
 
where sid = (select sid from v$mystat where rownum = 1))) s ;
 
 
prompt &trace_file
 
prompt &trace_file
 +
</source>
 
   
 
   
SQL*Plus의 column 명령을 이용해서 Trace File의 이름을 얻어내는 기법을 유심히 보자.
+
* SQL*Plus의 column 명령을 이용해서 Trace File의 이름을 얻어내는 기법을 유심히 보자.
잘 응용하면 많은 작업들을 SQL*Plus 내에서 자동화시킬 수 있다. Host Command로
+
:* 잘 응용하면 많은 작업들을 SQL*Plus 내에서 자동화시킬 수 있다.  
tkprof를 호출하면 Formatting된 Report를 얻을 수 있다.
+
:* Host Command로 tkprof를 호출하면 Formatting된 Report를 얻을 수 있다.
 +
<source lang=shell>
 
-- tkprof.sql
 
-- tkprof.sql
 
Ho tkprof &trace_file &1
 
Ho tkprof &trace_file &1
+
</source>
3. 10053 Event
 
 
10053 Event은 CBO 문제를 추적하는 가장 강력한 Tool이다. 하지만 자주 사용되지는 않는 이유는 무엇보다도
 
더 쉽고 좋은 방법이 많기 때문이다.
 
- EXPLAIN PLAN 명령, GATHER_PLAN_STATISTICS Hint, DBMS_XPLAN Package 등을 이용
 
  (CBO 문제의 핵심인 실행 계획 이상 현상을 상당 부분 추적)
 
- CBO가 Optimization 단계에서 수행하는 일은 결국 통계 정보를 읽어서 최적의 Cost를 계산하는 일에 불과하다.
 
  따라서 통계 정보를 정확하게 이해하고 있다면 CBO가 하는 일을 해할 수 있다. ALL_TAB_STATISTICS, ALL_IND_STATISTICS,
 
  ALL_TAB_COL_STATISTICS, ALL_PART_COL_STATISTICS, ALL_SUBPART_COL_STATISTICS, ALL_TAB_HISTOGRAMS,
 
  ALL_PART_HISTOGRAMS, ALL_SUBPART_HISTOGRAMS Dictionary View를 조회하면 통계 정보를 확인 할 수 있다.
 
 
하지만 Oracle CBO가 점점 세련되어지고 복잡해지면서 EXPLAIN PLAN이나 DBMS_XPLAN Package만으로는 원하는 정보를
 
충분히 얻기가 점점 어려워지고 있다.(10053 Event 필요성이 증가)
 
10053 Event의 출력 결과가 제공하는 정보
 
- CBO가 참조하는 기본 환경 값을 알 수 있다. Optimizer와 관련된 Parameter/Bug Fix Patch 등을 확인
 
- Query Transformation 과정을 알 수 있 다. 복잡한 SQL 문장이 어떻게 Transformation 되는지
 
  왜 Transformation에 실패하는지에 대한 정보를 제공.
 
- Query Optimization 과정을 알 수 있다. System Statistics와 Object Statistics를 참조하는 일련의 과정과
 
  Access Type의 결정, Join Type을 결정하는 일련의 과정이 출력
 
 
4. 기본적인 사용법
 
 
10053 Event의 사용 방법을 보자.
 
alter session set events ‘10053 trace name context forever, level 1’;
 
<Query>
 
alter session set events ’10053 trace name context off’;
 
 
출력 결과는 User Dump Directory에 Trace File 형태로 기록되며 내용은 Version마다 상이하다. 최신 버전의 Trace File은
 
다음과 같은 내용을 기록한다.
 
- Query Block 생성
 
- Optimizer Parameter, Bug Fix Control 정보
 
- Query Transformation 과정
 
- Statistics 정보
 
- Single Table Access 방식 선택
 
- Join 순서와 Join방식 선택
 
 
각 단계별로 어떤 내용이 기록되는지 예제를 통해서 확인하자. 우선 필요한 Object 들을 생성
 
 
test_script32.sql
 
 
Query를 수행하고, Plan Statistics를 조회
 
test_script33.sql
 
PLAN_TABLE_OUTPUT
 
-------------------------------------
 
SQL_ID 07fq9jjq9p0qs, child number 0
 
-------------------------------------
 
select /*+ gather_plan_statistics cost_based */ t1.name, v1.name2 , v1.name2 from t_pred1 t1, v_pred v1 where t1.n = 1 and t1.id = v1.id2_1(+)
 
 
Plan hash value: 3337020919
 
------------------------------------------------------------------------------------------------------------------------------------------------------------
 
| Id  | Operation                  | Name      | Starts | E-Rows |E-Bytes| Cost (%CPU)| E-Time | A-Rows |  A-Time  | Buffers |  OMem |  1Mem | Used-Mem |
 
------------------------------------------------------------------------------------------------------------------------------------------------------------
 
|  0 | SELECT STATEMENT          |            |      1 |        |      |    45 (100)|        |    20 |00:00:00.09 |    173 |      |      |          |
 
|*  1 |  HASH JOIN OUTER          |            |      1 |    20 |  880 |    45  (5)|00:00:01|    20 |00:00:00.09 |    173 |  1133K|  1133K|  961K (0)|
 
|*  2 |  TABLE ACCESS FULL        | T_PRED1    |      1 |    20 |  280 |    3  (0)|00:00:01|    20 |00:00:00.01 |      3 |      |      |          |
 
|  3 |  VIEW                    | V_PRED    |      1 |  20000 |  585K|    42  (5)|00:00:01|  20000 |00:00:00.05 |    170 |      |      |          |
 
|*  4 |    HASH JOIN              |            |      1 |  20000 |  800K|    42  (5)|00:00:01|  20000 |00:00:00.05 |    170 |  1647K|  1647K| 2249K (0)|
 
|  5 |    INDEX FAST FULL SCAN  | T_PRED3_IDX|      1 |  20000 |  195K|    14  (0)|00:00:01|  20000 |00:00:00.01 |      61 |      |      |          |
 
|  6 |    TABLE ACCESS FULL      | T_PRED2    |      1 |  20000 |  605K|    26  (0)|00:00:01|  20000 |00:00:00.01 |    109 |      |      |          |
 
------------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
Query Block Name / Object Alias (identified by operation id):
 
-------------------------------------------------------------
 
  1 - SEL$1
 
  2 - SEL$1 / T1@SEL$1
 
  3 - SEL$2 / V1@SEL$1
 
  4 - SEL$2
 
  5 - SEL$2 / T3@SEL$2
 
  6 - SEL$2 / T2@SEL$2
 
 
Predicate Information (identified by operation id):
 
---------------------------------------------------
 
  1 - access("T1"."ID"="V1"."ID2_1")
 
  2 - filter("T1"."N"=1)
 
  4 - access("T2"."ID"="T3"."ID" AND "T2"."ID2"="T3"."ID2")
 
 
Column Projection Information (identified by operation id):
 
-----------------------------------------------------------
 
  1 - (#keys=1) "T1"."NAME"[VARCHAR2,30], "V1"."NAME2"[VARCHAR2,30]
 
  2 - "T1"."ID"[NUMBER,22], "T1"."NAME"[VARCHAR2,30]
 
  3 - "V1"."ID2_1"[NUMBER,22], "V1"."NAME2"[VARCHAR2,30]
 
  4 - (#keys=2) "T2"."ID"[NUMBER,22], "T2"."NAME"[VARCHAR2,30]
 
  5 - "T3"."ID"[NUMBER,22], "T3"."ID2"[NUMBER,22]
 
  6 - "T2"."ID"[NUMBER,22], "T2"."ID2"[NUMBER,22], "T2"."NAME"[VARCHAR2,30]
 
실행 계획에서 유의해서 봐야 할 정보는 Predicate 정보이다. 정보는 다음과 같이 해석할 수 있다.
 
- 2번 단계(t1.n = 1)에서 Table Full Scan을 통해 조건을 만족하는 Row를 Fetch
 
- 4번 단계(v_pred.t2.id = t3.id and t2.id2 = t3.id2)에서 Hash Join을 통해 조건을 만족하는 Row를 Fetch
 
- 1번 단계(t1.id = v1.id2_1)에서 Hash Outer Join을 통해 2번과 4번 단계의 Data들을 Join
 
 
정상적인 결과로 보이는 위의 실행 계획의 문제점은 Join Predicate Pushing이 발생하지 않았다는 것이다.
 
t1.n = 1의 조건을 만족하는 Data에 대해서 Join 조건(Join Predicate)을 View v_pred 안으로 밀어 넣을
 
수(Pushing)있다면 일량을 줄일 수 있다.
 
 
Predicate 정보의 변화에 주목하자. Join Predicate Pushing이라는 이름의 Query Transformation
 
기법으로 인해 t2.id = t1.id라는 기존에 존재하지 않던 Join 조건이 추가되었고 실행 계획이 크게 변한다.
 
10053 Event를 이용해 왜 Query Transformation, 즉 Join Predicate Pushing이 발생하지 않았는지를
 
추적하는 것이다.
 
 
단계 1 : Trace File은 Query Block정보를 생성하는 것에서부터 시작. SQL 문장에 대해 Parse Tree를
 
생성하는 과정에서 기본적인 Query Block 정보가 생성. 사용된 Query Block명이 Plan Statistics에서
 
보이는 Query Block Name 정보와 일치한다. Query Transformation에 의해 Query Block정보가
 
바뀌는 경우에는 최종 Query Block 개수와 이름이 변경될 수 있다.
 
(Trace 파일 일부분을 발췌해봤다.)
 
 
Registered qb: SEL$1 0x2f2feae0 (PARSER)
 
  signature (): qb_name=SEL$1 nbfros=2 flg=0
 
    fro(0): flg=4 objn=66336 hint_alias="T1"@"SEL$1"
 
    fro(1): flg=5 objn=66341 hint_alias="V1"@"SEL$1"
 
Registered qb: SEL$2 0x2f2f61b0 (PARSER)
 
  signature (): qb_name=SEL$2 nbfros=2 flg=0
 
    fro(0): flg=4 objn=66337 hint_alias="T2"@"SEL$2"
 
    fro(1): flg=4 objn=66338 hint_alias="T3"@"SEL$2"
 
 
단계 2 : Parse Tree를 Query Block이 부여되고 나면 Optimizer는 Parameter 정보와
 
Bug Fix Control 정보를 출력한다. 변경된 Parameter값과 기본 Parameter값이 순서대로 출력.
 
 
단계2 결과 참조.txt
 
 
Bug Fix Control 정보의 출력은 Oracle 10.2.0.2부터 출력. Bug Fix Control은 FIX CONTROL Parameter를 통해 수행.
 
이 Parameter 역시 Oracle10.2.0.2부터 지원되며 사용법은 다음과 같다.
 
 
ALTER SESSION SET "_FIX_CONTROL" = ’3746511:on’,’4519016:off’ ;
 
 
"Bug#3746511에 해당하는 Fix Control을 적용하라. 하지만 Bug#4519016에 해당하는 Fix Control은 적용하지 말라".
 
Bug Fix Control의 적용 여부에 따라 Optimizer의 안정성이 깨어지거나 비정상적인 동작을 하는 경우를 세밀하게 제어하기
 
위해 지원되는 기능이다. Bug Fix Control의 적용 여부는 V$SYSTEM_FIX_CONTROL View / V$SESSION_FIX_CONTROL View를
 
통해서도 조회 가능하다.
 
 
OPT_PARAM Hint에 의해 변경된 Optimizer Parameter 정보를 출력.
 
........
 
  _optimizer_starplan_enabled          = true
 
  _extended_pruning_enabled          = true
 
  _optimizer_push_pred_cost_based    = true
 
  _sql_model_unfold_forloops          = run_time
 
  _enable_dml_lock_escalation          = false
 
.........
 
 
SQL 문장 레벨에서 Optimizer Parameter 값을 제어하기 위한 목적으로 고안되었으며 Oracle10g R2부터 지원.
 
 
select /*+ opt_param('_optimizer_push_pred_cost_based','false') */
 
t1.name, v1.name2, v1.name2
 
from t_pred1 t1, v_pred v1
 
where t2.n = 1 and
 
t1.id = v1.id2_1(+);
 
 
단계 3 : 이제 본격적인 Optimization이 수행. 첫 단계로 Query Transformation 수행. Query Transformation은
 
QT(Query Transformation)와 CBQT(Cost Based Query Transformation)의 두 단계로 구분되며, QT 단계에서는
 
Cost 계산이 불필요한 간단한 Transformation을 수행.
 
 
단계3 결과 참조_1.txt
 
 
Oracle Version에 따라 Transformation 기법이 추가되거나 개선되기 때문에 이 정보는
 
 
 
Version 에 따라 크게 다를 수 있다. QT 단계가 끝나면 CBQT 가 수행된다.
 
  
+
== 바인드변수 추적 V$SQL_BIND_CAPTURE ==
단계3 결과 참조_2.txt
+
# '''V$SQL_BIND_CAPTURE''' View를 통해 Bind 변수를 확인 가능
+
#:* 15분 간격으로 Capture를 수행.  
CBQT는 Cost를 감안해서 Transformation을 수행해야 한다. 이것은 Transformation 단계에서 실제
+
#:* Capture주기는 '''_CURSOR_BIND_CAPTURE_INTERVAL''' Parameter값에 의해 결정.
 
+
#:* 기본값 : 900 () , 이 값을 줄임으로써 보다 공격적으로 Capture를 수행할 수 있다. 약간의 성능 저하를 감수해야 한다.
Transformation이 일어나지 않고 Cost가 계산되는 Optimization 단계에서 Transformation이 이루어진다는
+
#:** 아무리 Capture 주기를 줄인 다고 해도 모든 SQL 문장의 Bind 변수를 Capture 하는 것은 불가능.
 
+
#:* 하나의 SQL Cursor에 대해 정해진 메모리 크기만큼만 Bind Capture를 수행.  
것을 의미 한다. CBQT의 등장과 함께 Transformation 단계와 Optimization 단계의 융합(Fusion)이
+
#:** 메모리 크기의 한계는 '''_CURSOR_BIND_CAPTURE_AREA_SIZE''' Parameter 값에 의해 결정.(기본값 : 2000(Byte))
 
+
# 많은 수의 Bind 변수를 사용하는 경우, '''V$SQL_BIND_CAPTURE''' View에 일부 Bind 변수 값이 누락되는 현상이 발생할 수 있는데 이런 제약 조건 때문이다.
이루어진 것이다. 예제와 같이 Optimization이 이루어지는 도중에 실제 Transformation을 수행한다.
+
#:* Oracle은 Select 문장과 '''Bind 변수가 Where 절에서 사용되었을 경우에만''' Bind Capture를 수행.
 
+
#:* V$SQL_BIND_CAPTURE View는 '''가장 최근에 Capture된 Bind 변수 값'''을 보여준다.(Extended SQL Trace와 같은 역할은 불가능)
(첨부파일 내용은 책의 내용을 복사한 것이다.)
 
 
 
단계3 결과 참조_3.txt
 
 
 
첨부파일의 마지막 줄 "JPPD: Will not use JPPD from query block SEL$1 (#1)" Message에 주목하자.
 
 
 
이 Message는 CBQT에 의해 JPPD(Join Predicate Push Down)이 이루어진 경우의 Cost가 더 높기
 
 
 
때문에 JPPD를 수행하지 않을 것임을 의미한다. 이 정보는 10053 Event에서만 얻을 수 있다.
 
 
 
10053 Event를 수행해야 할 가장 중요한 이유 중 하나가 Transformation (CBQT 포함)
 
 
 
Troubleshooting이 될 것이다.
 
 
 
CBQT의 수행 여부는 _OPTIMIZER_COST_BASED_TRANSFORMATION Parameter /
 
 
 
_OPTIMIZER_PUSH_PRED_COST_BASED Parameter값에 의해 결정된다. CBQT를 Disable 시키려면
 
 
 
Parameter 값을 변경해 주면 된다.
 
 
 
 
-- disable CBQT
 
 
 
alter session set "_optimizer_cost_based_transformation" = off;
 
 
-- disable cost based join predicate pushing
 
alter session set "_optimizer_push_pred_cost_based" = false;
 
 
SQL 문장 레벨에서 CBQT를 Disable 하려면 OPT PARAM Hint를 사용하면 된다.
 
 
select /*+ opt_param(‘_optimizer_push_pred_cost_based’,’false’) */
 
 
 
t1.name, v1.name2, v1.name2
 
 
 
from t_pred1 t1, v_pred v1
 
 
 
where t1.n = 1 and t1.id = v1.id2_1(+);
 
 
 
 
 
 
단계 4: Statistics 정보를 추출하고, Optimization을 위한 기본적인 정보들을 계산한다. Optimization의 기본 단위는
 
 
 
SQL 문장 전체가 아니라 Query Block이다. CBO는 Query Block 레벨에서 Optimization을 수행하고 그 결과를
 
 
 
다시 상위 Query Block에서 사용하는 방식을 사용한다. 예제는 Optimization 과정이 Query Block 들의 단위로
 
 
 
나누어 기록된다.
 
 
 
(첨부파일 내용 역시 책의 내용을 복사한 것이다.)
 
 
 
 
 
 
단계4 결과 참조_1.txt
 
 
 
 
 
 
System Statistics는 SYS.SYS_AUX$ Table에 저장되어 있다.
 
 
 
Select * from sys.sys_aux$;
 
 
 
(직접 실행은 해봤지만 테이블이 존재하지 않는다는 메세지가 출력 됬다. 직접 조회해보기 바란다.)
 
 
 
그 후 Dictionary View를 통해 Object Statistics 정보를 추출한다. Table에 대해서는 Row수, Block수, 평균 Row 크기
 
 
 
등의 정보를 추출한다. Index에 대해서는 Level(Depth), Distinct Key의 개수, Leaf Block수, Clustering Factor 등의 정보를 추출한다.
 
 
 
 
 
 
단계4 결과 참조_2.txt
 
 
 
 
 
 
단계 5: Statistics에서 추출한 정보는 Single Table Access 방식을 판단하는 기준으로 사용된다.
 
 
 
Single Table Access의 Cost를 계산하는 작업은 특정 Query Block 단위로 이루어진다. Query Block 내에 속한
 
 
 
Table과 Predicate(조건)에 대해 최적의 Access 방식을 산출. Access 방식은 Table Full Scan, Index Unique / Range Scan,
 
 
 
Index Full Scan, Index Fast Full Scan, Index Skip Scan, Index Join, Index Combination에서 선택.
 
 
 
 
 
 
단계5 결과 참조_1.txt
 
 
 
 
 
 
Table t_pred2에 대한 최적의 Access 방식은 Table Full Scan이며 Cost는 29.55이다. 반면, Table t_pred3에
 
 
 
대한 최적의 Access 방식은 Index t_pred3_idx를 Index Fast Full Scan으로 읽는 것이며, Cost는 15.33이다.
 
 
 
 
 
 
단계5 결과 참조_2.txt
 
 
 
 
 
 
특정 Table에 대해 Parallel 작업이 수행되는 경우 다음 정보가 출력 된다. Serial Cost(Cost):3,
 
 
 
Parallel Cost(Resp):2로 계산된다. 따라서 Parallel Execution이 선택될 것이다.
 
 
 
 
 
 
select /*+ parallel(t1 4) */
 
 
 
t1.name, v1.name2, v1.name2
 
 
 
from t_pred1 t1, v_pred v1
 
 
 
where t1.n = 1 and t1.id = v1.id2_1(+);
 
 
 
 
 
 
SINGLE TABLE ACCESS PATH
 
 
 
Column (#2) : N(NUMBER)
 
 
 
AvgLen : 3.00 NDV : 5 Nulls : 0 Density:0.2 Min : 1 Max : 5
 
 
 
Table : T_PRED1 Alias : T1
 
 
 
Card : Original : 100 Rounded : 20 Computed : 20.00 Non Adjusted : 20.00
 
 
 
Access Path : TableScan
 
 
 
Cost : 2.00 Degree : 4 Resp : 2.00 Card : 20.00 Bytes : 0
 
 
 
통계 정보가 없거나 DYNAMIC_SAMPLING Hint가 사용되는 경우에는 Dynamic Sampling이 수행 된다.
 
 
 
Dynamic Sampling은 특정 Table에 대해 주어진 Block 수(32)만큼 Sampling을 수행. Table에 대해 사용된
 
 
 
Predicate를 확인해서 예상 Row수를 계산. 복잡한 Predicate에 대해 좀 더 정확한 예측이 가능.
 
 
 
Dynamic Sampling이 사용된 경우에는 Single Table Access 정보에 내용이 추가로 출력.
 
 
 
 
 
 
select /*+ dynamic_sampling(t1 4) */
 
 
 
t1.name, v1.name2, v1.name2
 
 
 
from t_pred1 t1, v_pred v1
 
 
 
where t1.n = 1 and t1.id = v1.id2_1(+);
 
 
 
 
 
 
단계5 결과 참조_3.txt
 
 
 
 
 
 
Dynamic Sampling은 Query Block이 아닌 Table Level에서 이루어진다.(Dynamic Sampling의 근본적인 한계)
 
 
 
단계 6: 가장 중요한 단계로 Join 순서와 Join 종류를 결정. Join에 참여하는 Table들에 대해 Join 순서 별로 어떤 Join
 
 
 
방식이 가장 최적의 Cost를 갖는지 계산하게 된다.
 
 
 
 
 
 
단계6 결과 참조_1.txt
 
 
 
 
 
 
첫 번째 Join 순서로 {T2 -> T3}가 시도되며 NL Join, Sort Merge Join, Hash Join 중
 
 
 
Hash Join 이 최적의 Cost(45.97)를 지닌다. 두 번째 Join 순서인 {T3 ->T2}에 대해서도 같은 순서로 Cost를 계산하며,
 
 
 
동일한 Cost인 45.97이 계산되었기 때문에 첫 번째 Join 순서인 {T2 -> T3}+Hash Join이 최종 선택.
 
 
 
Join order[2] : T PRED3[T3]#1 T PRED2[T2]#0
 
 
 
Now joining : T PRED2[T2]#0
 
 
 
NL Join
 
 
 
outer table : Card : 20000.00 Cost : 15.33 Resp : 15.33 Degree : 1 Bytes : 10
 
 
 
Access path analysis for T_PRED2
 
 
 
Inner table : T_PRED2 Alias : T2
 
 
 
Access Path : TableScan
 
 
 
NL Join : Cost : 560929.09 Resp : 560929.09 Degree : 1
 
 
 
Cost_io : 550016.00 Cost_cpu : 91669966801
 
 
 
Resp_io : 550016.00 Resp_cpu : 91669966801
 
 
 
Access Path : index (AllEqJoinGuess)
 
 
 
Index : T_PRED2_IDX
 
 
 
resc_io : 2.00 resc_cpu : 15483
 
 
 
   
 
 
 
Trace 내용 참고.txt
 
 
 
 
 
 
(이하 내용이 너무 많아 별도의 첨부파일을 등록했다 참고 바란다.)
 
 
 
Query 유형과 무관하게 CBO는 항상 6 단계에 따라 최적의 Cost를 갖는 실행 계획을 선택하게 된다.
 
 
 
DBMS_XPLAN Package의 결과를 볼 때 위의 과정을 그려본다면 실행 계획을 이해하는데 도움이 될 수 있다.
 
 
 
10053 Event는 Query에 대해 Hard Parse(혹은 Optimization)가 발생할 때만 수행된다. Query가 수행될 때마다
 
 
 
활성화되는 10046 Event와 확실히 구별된다. 간혹 특정 SQL 문장만 Hard Parse를 유발하고 싶은 경우가 생긴다.
 
 
 
이것은 Oracle 10.2.0.4부터는 가능하다. DBM5-SHARED_POOL.PURGE Procedure가 이 기능을 제공한다.
 
 
 
DBMS_SHARED_POOL.PURGE Procedure의 사용법은 다음과 같다.
 
 
 
(자세한 사용법은 http://wiki.ex-em.com/index.php/DBMS_SHARED_POOL.PURGE을 참고하자).
 
 
 
--특정 SQL Cursor를 Purge
 
 
 
select address, hash value
 
 
 
from v$sqlarea
 
 
 
where sql_text like ’....’;
 
 
 
ADDRESS    HASH VALUE
 
 
 
-----------    ---------------
 
 
 
2F4651EC    3900782439
 
 
 
exec sys.dbms_shared_pool.purge(‘2F4651EC.3900782439’,’C’);
 
 
 
--특정 Procedure를 purge 할 때
 
 
 
exec sys.dbms_shared_pool.purge(‘USER.TEST_PROC’,’P’);
 
 
 
 
 
 
| Examples |
 
 
 
예제를 통해 10053 Event 의 유용함과 Trace File 해석의 중요성을 확인 하자.
 
 
 
사악한 ROWNUM
 
 
 
첫 번째 예제는 ROWNUM에 의한 실행 계획 변화 문제를 추적하는 것이다. Object를 생성.
 
 
 
 
 
 
test_script34.sql
 
 
 
 
 
 
아래 두 SQL 문장의 유일한 차이는 Inline View의 특정 단계에서의 ROWNUM 연산자의 사용 여부이다.
 
 
 
 
 
 
test_script35.sql
 
 
 
 
 
 
(Rownum을 사용하지 않은 경우의 결과)
 
 
 
PLAN_TABLE_OUTPUT
 
-----------------------------------------------------------------------------------
 
Plan hash value: 1743147828
 
-----------------------------------------------------------------------------------
 
| Id  | Operation                    | Name | Rows | Bytes | Cost (%CPU)| Time  |
 
-----------------------------------------------------------------------------------
 
|  0 | SELECT STATEMENT              |      |    1|    41 |    8  (25)|00:00:01|
 
|  1 |  SORT AGGREGATE              |      |    1|    41 |            |        |
 
|  2 |  VIEW                        |      |    1|    41 |    8  (25)|00:00:01|
 
|  3 |    HASH GROUP BY              |      |    1|    91 |    8  (25)|00:00:01|
 
|* 4 |    HASH JOIN                |      |    1|    91 |    7  (15)|00:00:01|
 
|  5 |      MERGE JOIN CARTESIAN    |      |    1|    65 |    4  (0)|00:00:01|
 
|*  6 |      TABLE ACCESS FULL      |  T1 |    1|    39 |    2  (0)|00:00:01|
 
|  7 |      BUFFER SORT            |      |    1|    26 |    2  (0)|00:00:01|
 
|  8 |        TABLE ACCESS FULL      |  T3 |    1|    26 |    2  (0)|00:00:01|
 
|  9 |      TABLE ACCESS FULL        |  T2 |    1|    26 |    2  (0)|00:00:01|
 
-----------------------------------------------------------------------------------
 
 
Predicate Information (identified by operation id):
 
---------------------------------------------------
 
  4 - access("T1"."C1"="T2"."C1" AND "T2"."C1"="T3"."C1")
 
  6 - filter("T1"."C2"=1)
 
 
Note
 
-----
 
  - dynamic sampling used for this statement
 
 
 
test_script36.sql
 
 
(Rownum을 사용한 경우의 결과)
 
 
 
PLAN_TABLE_OUTPUT
 
------------------------------------------------------------------------------------
 
Plan hash value: 472191378
 
------------------------------------------------------------------------------------
 
| Id  | Operation                    | Name | Rows  | Bytes | Cost (%CPU)| Time    |
 
------------------------------------------------------------------------------------
 
|  0 | SELECT STATEMENT            |      |  1    |    41 |    8  (25)| 00:00:01|
 
|  1 |  SORT AGGREGATE              |      |  1    |    41 |            |        |
 
|  2 |  VIEW                      |      |  1    |    41 |    8  (25)| 00:00:01|
 
|  3 |    VIEW                      |      |  1    |    52 |    8  (25)| 00:00:01|
 
|  4 |    VIEW                    |      |  1    |    52 |    8  (25)| 00:00:01|
 
|  5 |      VIEW                    |      |  1    |    52 |    8  (25)| 00:00:01|
 
|  6 |      HASH GROUP BY          |      |  1    |    91 |    8  (25)| 00:00:01|
 
|* 7 |        HASH JOIN            |      |  1    |    91 |    7  (15)| 00:00:01|
 
|  8 |  MERGE JOIN CARTESIAN        |      |  1    |    65 |    4  (0)| 00:00:01|
 
|* 9 |  TABLE ACCESS FULL          | T1  |  1    |    39 |    2  (0)| 00:00:01|
 
|  10 |  BUFFER SORT                |      |  1    |    26 |    2  (0)| 00:00:01|
 
|  11 |    TABLE ACCESS FULL        | T3  |  1    |    26 |    2  (0)| 00:00:01|
 
|  12 |  TABLE ACCESS FULL          | T2  |  1    |    26 |    2  (0)| 00:00:01|
 
------------------------------------------------------------------------------------
 
Predicate Information (identified by operation id):
 
---------------------------------------------------
 
  7 - access("T1"."C1"="T2"."C1" AND "T2"."C1"="T3"."C1")
 
  9 - filter("T1"."C2"=1)
 
Note
 
-----
 
  - dynamic sampling used for this statement
 
 
위 결과는 책의 결과와는 조금 다르다.
 
 
 
실행 계획의 가장 큰 차이는 어디에 있는가? Predicate 정보에서 ROWNUM이 사용되지 않은 첫 번째 경우
 
 
 
"6 - filter("T1"."C2"=1)" 조건이 사용되었다. 반면 ROWNUM이 사용된 두 번째 경우에는 "filter(" PUSH_KEY" = 1)"
 
 
 
조건이 사용되었다. 이것은 무엇을 의미하는가?
 
 
 
- ROWNUM이 사용되지 않은 경우 : push_key = 1 조건이 View 안으로 Push(실제 조건인 t1.c2 = 1 조건으로 변환
 
 
 
- ROWNUM이 사용된 경우 : push_key = 1 조건이 View 안으로 Push 되지못하고 View가 다 처리된 후 마지막에 적용
 
 
 
ROWNUM의 사용으로 인해 push_key = 1 조건이 View 안으로 Push 되지 않은 경우가 성능에 더 불리할 것이라는 것은
 
 
 
충분히 예측 가능할 것이다. 왜 이런 현상이 생겼는가? 이런 문제를 이미 경험한 사례가 있는 독자라면 ROWNUM을 사용함으로써
 
 
 
Query Transformation이 이루어지지 않았다는 것을 짐작할 수 있다. 10053 Event를 이용하면 CBO가 어떤 판단을 했는지(사실)
 
 
 
확인 할 수 있다. 아래는 두 번째 경우, ROWNUM이 사용된 경우에 Query Transformation에 어떤 영향을 미치는지를
 
 
 
10053 Event의 출력 결과를 발췌한 것이다.
 
 
 
 
 
 
Cost-Based Complex View Merging.txt
 
 
 
(책의 결과랑 다르므로 직접 확인해보자.)
 
 
 
우선 ROWNUM과 ORDER BY에 의해 CVM(Complex View Merging)이 이루어지지 않았다.
 
********************************
 
 
 
Predicate Move- Around (PM)
 
 
 
********************************
 
 
 
PM : Considering predicate move- around in SEL$1 (#1).
 
 
 
PM: Checking validity of predicate move-around in SEL$1(#1)
 
 
 
PM : PM bypassed : Reference to ROWNUM
 
 
 
PM : Passed validity checks
 
 
 
결정적으로 ROWNUM으로 인해 PM(Predicate Move-Around)가 실패했음을 알 수 있다.
 
 
 
PM이 성공적으로 이루어졌다면 push_key = 1 조건이 View 안으로 들어가서 보다 효율적인
 
 
 
실행 계획이 수립되었을 것이다. 하지만 예제를 보면 ROWNUM을 포함한 View에 대해서는
 
 
 
Predicate Pushing이 불가능하다.
 
 
 
Parallel or Not?
 
 
 
PARALLEL Hint를 사용함에도 불구하고 Parallel Query가 수행되지 않는 경우가 있다. 예제를 보자.
 
 
 
 
 
test_script37.sql
 
 
Primary Key를 갖는 Table이다. Parallel Query를 (기대하며) 수행한다.
 
 
test_script38.sql
 
 
PLAN_TABLE_OUTPUT
 
-----------------------------------------------------------------------
 
Plan hash value: 1018460547
 
-----------------------------------------------------------------------
 
| Id  | Operation            | Name  | Rows  | Cost (%CPU)| Time    |
 
-----------------------------------------------------------------------
 
|  0 | SELECT STATEMENT      |      |    1 |    6 (0)  | 00:00:01 |
 
|  1 |  SORT AGGREGATE      |      |    1 |            |          |
 
|  2 |  INDEX FAST FULL SCAN| T1_PK | 10000 |    6 (0)  | 00:00:01 |
 
-----------------------------------------------------------------------
 
 
하지만 기대와 달리 Parallel Query가 수행되지 않고 Index Fast Full Scan이 선택되었다.
 
 
 
Oracle이 PARALLEL Hint를 무시했나? 아니다. Oracle은 Hint를 절대 무시하지 않는다. 만일 Hint를
 
 
 
명시했는데도 동작하지 않았다면 Oracle이 Hint가 동작할 수 없는 상황이거나 Hint로 명시한 것보다
 
 
 
더 좋은 어떤 것을 발견했다는 의미이다. 10053 Event에 그 해답이 있다. 아래에 해당 Query에 대한
 
 
 
10053 Trace 결과가 있다.
 
 
 
--- Trace File 생성 후 결과 확인 ---
 
 
 
이 결과에서 다음과 같은 정보를 얻을 수 있다.
 
 
 
- Table Full Scan에 대한 Serial Cost(361.18), Parallel Cost(100.33) 이다.
 
 
 
- Index Fast Full Scan의 Cost(6.16)이다.
 
 
 
즉, PARALLEL Hint를 고려해서 Parallel Cost를 계산해 봤지만, Index Fast Full Scan의 Cost보다 훨씬 낮기 때문에
 
 
 
Index Fast Full Scan이 선택된 것이다. 이것이 PARALLEL Hint의 기본적인 동작 방식이다. Parallel Execution을
 
 
 
일방적으로 선택하는 것이 아니라 Parallel Cost를 낮춤으로써 선택 될 확률을 높이는 방식이다.
 
 
 
Oracle10g에서 Parallel Cost의 계산 공식은 다음과 같다.
 
 
 
Paralell Cost = (Serial Cost) / (Degree * 0.9)
 
 
 
재미있는 것은 다음과 같이 Primary Key를 삭제하고 Unique Index를 사용하면 Parallel Query가 선택 된다.
 
 
 
 
 
 
test_script39.sql
 
 
 
 
PLAN_TABLE_OUTPUT
 
---------------------------
 
Plan hash value: 3110199320
 
--------------------------------------------------------------------------------------------------------
 
| Id  | Operation                  | Name  | Rows  | Cost (%CPU)| Time  |    TQ  |IN-OUT| PQ Distrib |
 
--------------------------------------------------------------------------------------------------------
 
|  0 | SELECT STATEMENT          |        |    1 |    88  (0)|00:00:02|        |      |            |
 
|  1 |  SORT AGGREGATE            |        |    1 |            |        |        |      |            |
 
|  2 |  PX COORDINATOR          |        |      |            |        |        |      |            |
 
|  3 |    PX SEND QC (RANDOM)    |:TQ10000|    1 |            |        |  Q1,00 | P->S | QC (RAND)  |
 
|  4 |    SORT AGGREGATE        |        |    1 |            |        |  Q1,00 | PCWP |            |
 
|  5 |      PX BLOCK ITERATOR    |        | 10000 |    88  (0)|00:00:02|  Q1,00 | PCWC |            |
 
|  6 |      TABLE ACCESS FULL    |  T1  | 10000 |    88  (0)|00:00:02|  Q1,00 | PCWP |            |
 
--------------------------------------------------------------------------------------------------------
 
 
 
 
Primary Key와 Unique Index사이에 어떤 차이점이 있는지 10053 Event를 통해 확인해 보자.
 
 
 
--- Trace File 생성 후 결과 확인 ---
 
 
 
놀랍게도 Index Fast Full Scan은 Cost계산에서 전혀 고려되지 않고 있다. 왜 그런가?
 
 
 
Primary Key와 Unique Index의 가장 큰 차이점에 답이 있다. Primary Key는 NOT NULL 조건을
 
 
 
암묵적으로 사용한다. Unique Index는 Column에 NULL값이 있다는 가정이 담겨 있다.
 
 
 
Unique Index는 "select count(*) from t1"과 같은Query에서는 사용될 수 없다. NULL 값이 누락되서
 
 
 
전체 Row수를 얻을 수 없기 때문에 Cost 계산 대상에서 아예 제외되어 버리는 것이다. NOT NULL 조건이
 
 
 
부여되면 다시 Index Fast Full Scan이 선택되는 것을 확인 할 수 있다.
 
 
 
 
  
test_script40.sql
+
== Wait 이벤트 현상을 Monitoring View ==
 +
{{틀:고지상자
 +
|제목=대기 이벤트 조회 관련 뷰
 +
|내용=
 +
# V$SESSION
 +
# V$SESSION_WAIT
 +
# V$SESSION_EVENT
 +
# V$SYSTEM_EVENT
 +
# V$ACTIVE_SESSION_HISTORY
 +
# DBA_HIST_ACTIVE_SESS_HISTORY
 +
# V$EVENT_HISTOGRAM
 +
}}
 +
* - 그 어떤 View도 10046 SQL Trace가 제공하는 것과 같은 포괄적인 추적 정보를 제공하지는 않는다.
  
PLAN_TABLE_OUTPUT
 
-----------------------------------------------------------------------
 
Plan hash value: 3675732849
 
  
-----------------------------------------------------------------------
+
----------
| Id  | Operation            | Name  | Rows  | Cost (%CPU)| Time    |
 
-----------------------------------------------------------------------
 
|  0 | SELECT STATEMENT      |      |    1 |    6 (0)  | 00:00:01 |
 
|  1 |  SORT AGGREGATE      |      |    1 |            |          |
 
|  2 |  INDEX FAST FULL SCAN| T1_N1 | 10000 |    6 (0)  | 00:00:01 |
 
-----------------------------------------------------------------------
 
[출처] Chap02.CBO Tools Part.02 (ProDBA) |작성자 디비
 
 
[[category:oracle]]
 
[[category:oracle]]

2024년 1월 23일 (화) 17:30 기준 최신판

thumb_up 추천메뉴 바로가기


1 10046 Event[편집]

record_voice_over 10046 Event는 SQL Tuning에 있어서 필요한 Tool인가?

  • Plan Statistics가 제공하지 못하는 중요한 정보를 제공해주기 때문
- 모든 SQL 문장의 Bind 변수 값을 추적할 수 있는 유일한 방법(Level 4)
- 모든 SQL 문장의 대기 현상(Wait)을 추적할 수 있는 유일한 방법(Level 8)


1.1 10046 trace 실행 절차[편집]

1.1.1 트레이스 식별자 지정[편집]

alter session set tracefile_identifier='test'; ==> orcl_ora_10024_test.trc 형태로 저장됨.

1.1.2 sql trace 시작[편집]

ALTER SESSION SET SQL_TRACE = TRUE; -- level 1로 트레이스 활성화

1.1.3 event 를 level 12 로 설정[편집]

  • level 12 = (level 4 + 8) , SQL trace 정보, 실행계획, 바인드 변수, 대기 이벤트 정보를 볼 수 있다.
ALTER SESSION SET events '10046 trace name context forever, level 12';
  • 10046 = Query가 수행되는 이벤트. 즉 Query를 수행하는 "이벤트"를 의미.
  • trace name = Trace를 수행. 사건이 발생했을 때의 행위(Action)를 의미.
  • context forever, level 12 = 사건이 발생할 때마다 행위를 수행하되, 행위의 레벨을 12로

1.1.4 sql 실행[편집]

select * from tb_xxx;


1.1.4.1 sql trace 종료[편집]

ALTER SESSION SET SQL_TRACE = FALSE;


1.1.4.2 10046 event 끄기[편집]

  • 꺼주지 않으면, 수행하는 모든 SQL 에 대한 정보를 모은다.
  • level 0으로 지정해서 비활성화 하지 않는것에 유의할것.
ALTER SESSION SET events '10046 trace name context off';

1.2 10046 디버깅 이벤트 레벨[편집]

레벨 설명
0 디버깅 이벤트 비활성화
1
  1. 디버깅 이벤트 활성화
  2. DB 호출정보
  3. SQL구문,응답시간,서비스시간
  4. 처리 로우수,논리적 읽기 건수,물리적 읽기/쓰기 건수,실행계획
  5. 그외 추가적인 정보 제공
4
  1. 레벨1 제공정보 + 추가적인 바인드 변수 정보
  2. 데이터타입,정밀도,변수 값
8
  1. 레벨1 제공정보 + 추가적인 대기시간 정보
  2. 처리중 발생한 대기에 대한 정보
  3. 대기이벤트 이름,대기시간,대기 대상자원 식별
16
  1. 레벨1 제공정보 + 실행 계획의 STAT 정보
32
  1. 레벨1 제공정보에서 실행계획에 관한 정보만 제외 (11g 이상)
64
  1. 레벨1 제공정보 + 첫번째 실행 후에도 실행 계획 정보 기록
  2. 실행 계획 정보가 마지막으로 기록된 이후 특정 커서가 최소 1분이상 DB실행 시간이 소요되는경우
  3. 레벨 16에서 모든 실행에 대한 정보를 기록하는 오버헤드가 클경우 사용 (11g 이상)
  • 레벨을 조합하여서 사용할 수 있음.(레벨 1을 제외한 조합 가능)
    • 레벨 12(4 + 8) : 레벨 4 + 레벨 8을 동시에 활성화
    • 레벨 28(4 + 8 + 16) : 레벨 4 + 레벨 8 + 레벨 16 을 동시에 활성화
    • 레벨 68(4 + 64) : 레벨 4 + 레벨 64을 동시에 활성화

1.3 10046 Event Trace 자동화[편집]

  • 10046 Event를 이용해 SQL Trace 수행을 자동화 스크립트
Connect …
@trace on 10046 8
-- execute query
select *
from …
where …
@trace_off
@trace_file
@tkprof trc.out
ed trc.out
trace_on.sql과 trace_off.sql Script는 Event 을 활성화 / 비활성화하는 역할.
-- trace on.sql
alter session set events ‘&1 trace name context forever, level &2’;
-- trace off.sql
alter session set events ’&1 trace name context off’;
자동화의 핵심은 trace_file의 이름을 얻는데 있다.
-- @name : trace file
-- @author : dion cho
-- @description : get trace file name
column trace file name new value trace file
select
-- 아래 부분은 환경에 맞게 적절히 수정
d.value ||’/’||p.value||’_ora_’||s.spid||’.trc’as trace_file_name
from (select value from v$parameter where name = ’instance_name’) p
   , (select value from v$parameter where name = ‘user_dump_dest’) d
   , (select spid from v$process where addr = (select paddr from v$session where sid = (select sid from v$mystat where rownum = 1))) s 
;
prompt &trace_file
  • SQL*Plus의 column 명령을 이용해서 Trace File의 이름을 얻어내는 기법을 유심히 보자.
  • 잘 응용하면 많은 작업들을 SQL*Plus 내에서 자동화시킬 수 있다.
  • Host Command로 tkprof를 호출하면 Formatting된 Report를 얻을 수 있다.
-- tkprof.sql
Ho tkprof &trace_file &1

1.4 바인드변수 추적 V$SQL_BIND_CAPTURE[편집]

  1. V$SQL_BIND_CAPTURE View를 통해 Bind 변수를 확인 가능
    • 15분 간격으로 Capture를 수행.
    • Capture주기는 _CURSOR_BIND_CAPTURE_INTERVAL Parameter값에 의해 결정.
    • 기본값 : 900 (초) , 이 값을 줄임으로써 보다 공격적으로 Capture를 수행할 수 있다. 약간의 성능 저하를 감수해야 한다.
      • 아무리 Capture 주기를 줄인 다고 해도 모든 SQL 문장의 Bind 변수를 Capture 하는 것은 불가능.
    • 하나의 SQL Cursor에 대해 정해진 메모리 크기만큼만 Bind Capture를 수행.
      • 메모리 크기의 한계는 _CURSOR_BIND_CAPTURE_AREA_SIZE Parameter 값에 의해 결정.(기본값 : 2000(Byte))
  2. 많은 수의 Bind 변수를 사용하는 경우, V$SQL_BIND_CAPTURE View에 일부 Bind 변수 값이 누락되는 현상이 발생할 수 있는데 이런 제약 조건 때문이다.
    • Oracle은 Select 문장과 Bind 변수가 Where 절에서 사용되었을 경우에만 Bind Capture를 수행.
    • V$SQL_BIND_CAPTURE View는 가장 최근에 Capture된 Bind 변수 값을 보여준다.(Extended SQL Trace와 같은 역할은 불가능)

1.5 Wait 이벤트 현상을 Monitoring View[편집]

  1. V$SESSION
  2. V$SESSION_WAIT
  3. V$SESSION_EVENT
  4. V$SYSTEM_EVENT
  5. V$ACTIVE_SESSION_HISTORY
  6. DBA_HIST_ACTIVE_SESS_HISTORY
  7. V$EVENT_HISTOGRAM


  • - 그 어떤 View도 10046 SQL Trace가 제공하는 것과 같은 포괄적인 추적 정보를 제공하지는 않는다.