프로파일링 데이터를 얻고 리포팅하는 기본적인 방법
프로파일링 데이터와 리포트를 만드는 간단한 예제
-- STEP1. 세션#1 에서 ALL_OBJECTS뷰를 읽는 작업을 수행
SQL> -- session #1
SQL> exec dbms_application_info.set_client_info('session1');
PL/SQL 처리가 정상적으로 완료되었습니다.
SQL> select count(*) from all_objects;
COUNT(*)
----------
60080
-- STEP2. 세션#1 이 작업을 수행하는 동안 세션 #2로 부터 세션1이 어떤 대기 이벤트(WaitEvent)을 대기하는지 프로파일링하는게 예제의핵심
-- 1) 우선 세션#2에서 세션#1의 세션아이디(SID)값을 얻음
SQL> -- session #2
SQL> col sid new_value sid
SQL> select sid from v$session where client_info = 'session1';
SID
----------
12
-- STEP3. 총 1,000회 걸쳐 V$SESSION_WAIT뷰를 반복적으로 읽으면서 대기 이벤트를 얻음
-- 즉 대기 이벤트 정보를 프로파일링 함
SQL> set serveroutput on
SQL> declare
2 v_sw v$session_wait%rowtype;
3 begin
4 for idx in 1 ... 1000 loop
5 begin
6 select * into v_sw
7 from v$session_wait
8 where sid = &sid
9 and state = 'WAITING';
10
11 dbms_output.put_line(
12 'event = ' || v_sw.event ||
13 ', seq# = '|| v_sw.seq# ||
14 ', p1 = ' || v_sw.p1 ||
15 ', elapsed = ' ||
16 trunc(v_sw.wait_time_micro/1000,2) || '(ms)');
17
18 exception when others then null;
19
20 end;
21 end loop;
22 end;
23 /
-- STEP4. 그결과 아래와 같이 대기 이벤트 목록을 얻을 수 있음
--
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72755.68(ms)
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72755.76(ms)
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72755.84(ms)
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72755.91(ms)
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72755.99(ms)
event = SQL*Net message from client, seq# = 39, p1 = 1111838976, elapsed = 72756.07(ms)
프로파일링 데이터에 대해 대기이벤트를 기준으로 히트(Hit) 회수를 집계하는 방법
-- STEP1.우선 프로파일링 데이터를 저장할 테이블 SESSION_WAIT를 만듬
SQL> create table session_wait as select * from v$session_wait where 1=0;
테이블이 생성되었습니다.
-- STEP2. 세션#1 에 대해 대기 이벤트를 프로파일링하면서 그 결과를 테이블 SESSION_WAIT에 저장함
SQL> begin
2 for idx in 1 .. 1000 loop
3
4 insert into session_wait
5 select *
6 from v$session_wait
7 where sid = &sid
8 and state = 'WAITING';
9
10 dbms_lock.sleep(0.001);
11 end loop;
12 end;
13 /
구 7: where sid = &sid
신 7: where sid = 12
PL/SQL 처리가 정상적으로 완료되었습니다.
-- STEP3. 프로파일링 결과가 테이블에 저장되어 있기 때문에 다음과 같이 손쉽게 집계리포트를 만들수 있음
-- 1) 집계(Summary)를 수행함으로써 어떤 대기 이벤트가 주로 발생했는지를 알수 있음
SQL> select event, count(*) as hits
2 from session_wait
3 group by event
4 order by 2 desc;
EVENT HITS
---------------------------------------------------------------- ----------
SQL*Net message from client 1000
-- STEP4. 위의 방법을 응용하면 테이블을 만들고 테이블에 INSERT하는 등의 번거로운 작업 없이
-- 하나의 쿼리로 동일한 결과의 리포트를 만들수 있음
SQL> select /*+ no_query_transformation ordered use_nl(w) */
2 w.event, count(*) as hits
3 from (select level from dual connect by level <= 50000) x,
4 (select decode(state, 'WAITING', event, 'ON CPU') as event
5 from v$session_wait
6 where sid = &sid) w
7 group by w.event
8 order by 2 desc;
EVENT HITS
---------------------------------------------------------------- ----------
SQL*Net message from client 50000
쿼리를 해석하는 방법
위와 같은 효과를 얻기 위해서 다음과 같은 힌트를를 사용하여 SQL제어함
대기 이벤트별 대기 회수와 대기 시간도 어느정도 측정할수 있는 예제
-- STEP1. 대기 이벤트별 대기 회수와 대기 시간 측정가능 SQL작성
SQL> -- session2
SQL> col event format a30
SQL> with w as (
2 select /*+ no_query_transformation ordered use_nl(w) */
3 w.event
4 , count(*) as hits
5 , count(distinct seq#) as dist_waits
6 , 5000 as total_hits
7 from (select level from dual connect by level <= 50000) x
8 , (select decode(state, 'WAITING', event, 'ON CPU') as event
9 , decode(state, 'WAITING', seq#, 0) as seq#
10 from v$session_wait
11 where sid = &sid) w
12 group by w.event
13 order by 2 desc
14 )
15 select /*+ ordered */
16 w.event
17 , trunc(100*w.hits/w.total_hits,1) as wait_pct
18 , trunc((t2.gt - t1.gt)*w.hits/w.total_hits/100,2) as wait_time
19 , trunc((t2.gt - t1.gt)*w.hits/w.total_hits/w.dist_waits/100,3) as avg_wait_time
20 from (select dbms_utility.get_time as gt from dual) t1
21 , w
22 , (select dbms_utility.get_time as gt from dual) t2
23 order by 2 desc;
-- STEP2. 아래에 그 결과가 있음
EVENT WAIT_PCT WAIT_TIME AVG_WAIT_TIME
------------------------------ ---------- ---------- -------------
SQL*Net message from client 1000 4.1 4.1
쿼리를 해석하는 방법
10046 진단 이벤트 정의
prompt> oerr 10046
"enable SQL statement timing"
// *Cause:
// *Action:
10046 진단 이벤트에 의해 생성되는 프로파일링 데이터를 확인
-- STEP1. 10046 진단 이벤트를 활성화한 상태에서 쿼리를 수행함
SQL> alter session set events '10046 trace name context forever, level 8';
세션이 변경되었습니다.
SQL> select count(*) from all_objects;
COUNT(*)
----------
60081
SQL>
SQL> alter session set events '10046 trace name context off';
세션이 변경되었습니다.
/**
-- STEP2. 10046 진단 이벤트에 의해 생성된 프로파일링 데이터는 서버 프로세스의 트레이스 파일에 기록됨
-- 아래 데이터를 보면 앞서 매뉴얼 프로파일링을 통해서 얻은 데이터와 거의 유사항 포멧으로 기록되는 것을 알 수 있음
**/
PARSING IN CURSOR #4 len=32 dep=0 uid=52 oct=3 lid=52 tim=2454862187 hv=789896629 ad='220f54a4' sqlid='9tz4qu4rj9rdp'
select count(*) from all_objects
END OF STMT
PARSE #4:c=171601,e=256547,p=2,cr=258,cu=2,mis=1,r=0,dep=0,og=1,plh=1743485846,tim=2454862184
EXEC #4:c=0,e=150,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=1743485846,tim=2454862732
WAIT #4: nam='SQL*Net message to client' ela= 6 driver id=1111838976 #bytes=1 p3=0 obj#=-1 tim=2454862904
/**
-- STEP3. 프로파일링 데이터는 집계(Summary)를 통해서 의미있는 정보를 얻을수 있음
-- 10046 진단 이벤트에 의해 생성된 프로파일링 데이터는 TKPROF툴을 이용해 집계 리포트를 얻을수 있음
**/
D:\app_db\engine_oracle\diag\rdbms\ora11gr2\ora11gr2\trace>tkprof ora11gr2_ora_1312.trc ora11gr2_ora_1312.out
TKPROF: Release 11.2.0.1.0 - Development on 금 3월 2 09:07:49 2012
Copyright (c) 1982, 2009, Oracle and/or its affiliates. All rights reserved.
D:\app_db\engine_oracle\diag\rdbms\ora11gr2\ora11gr2\trace>noetpad ora11gr2_ora_1312.out
SQL ID: 9tz4qu4rj9rdp
Plan Hash: 1743485846
select count(*)
from
all_objects
call count cpu elapsed disk query current rows
------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.12 0.12 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 1.71 1.74 0 38115 0 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 1.84 1.87 0 38115 0 1
...(중략)
10053 진단 이벤트 정의
prompt> oerr 10053
"CBO Enable optimzier trace"
// *Cause:
// *Action:
10053 진단 이벤트에 의해 생성되는 프로파일링 데이터를 확인
-- STEP1. 10053 진단 이벤트를 활성화한 상태에서 쿼리를 수행함
SQL> alter session set events '10053 trace name context forever, level 1';
세션이 변경되었습니다.
SQL> select count(*) from all_objects where rownum = 1;
COUNT(*)
----------
1
SQL> alter session set events '10053 trace name context off';
세션이 변경되었습니다.
-- STEP2. 그리고 트레이스 파일의 내용을 확인해보면 옵티마이저가 수행하는 일련의 작업이 시간순으로 기록된 것을 알수 있음
-- 이런 데이터는 "왜 이런 실행계획이 만들어지는가?" 라는 의문을 해결할수 있는 가장 완벽한 정보를 제공함
SQL> @trace_file
-- STEP3. 10053 진단 이벤트에 의해 생성된 프로파일링 데이터(트레이스 파일)는 원본 데이터를 직접이용하는 것이 가장 보편적인 사용방법임
-- 하지만 필요하면 집계를 통해서 원하는 데이터를 얻을수있음
-- 예를 들어 아래와 같은 방법으로 트레이스 파일로 부터 조인 회수를 구할 수 있음
select count(*)
from table(tpack.get_tracefile_contents(tpack.get_tracefile_name))
where column_value like 'Now joining%';
- 강좌 URL : http://www.gurubee.net/lecture/4289
- 구루비 강좌는 개인의 학습용으로만 사용 할 수 있으며, 다른 웹 페이지에 게재할 경우에는 출처를 꼭 밝혀 주시면 고맙겠습니다.~^^
- 구루비 강좌는 서비스 제공을 위한 목적이나, 학원 홍보, 수익을 얻기 위한 용도로 사용 할 수 없습니다.