You are on page 1of 52

-------------------------------------------------------------------------------- File name: snapper4.

sql (Oracle Session Snapper v4) -- Purpose: An easy to use Oracle session-level performance measurement tool -which does NOT require any database changes nor creation of any -database objects! --This is very useful for ad-hoc performance diagnosis in environm ents -with restrictive change management processes, where creating -even temporary tables and PL/SQL packages is not allowed or woul d -take too much time to get approved. --All processing is done by a few sqlplus commands and an anonymou s -PL/SQL block, all that's needed is SQLPLUS access (and if you wa nt -to output data to server-side tracefile then execute rights on -DBMS_SYSTEM). Snapper only queries some V$ views (and in advance d -mode some X$ fixed tables, but it does not enable any traces nor -use oradebug. --The output is formatted the way it could be easily post-processe d -by either Unix string manipulation tools or loaded to spreadshee t. --Snapper v4 supports RAC and requires Oracle 10.1 or a newer DB v ersion. -Snapper v3.5 works on Oracle versions starting from Oracle 9.2 ( no RAC support) --- Note1: The "ASH" functionality in Snapper just samples GV$SESSION view, -so you do NOT need Diagnostics Pack licenses to use Snapper's -"ASH" output --- Note2: Snapper just reports you performance metric deltas in a snapspho t -and does not attempt to solve any performance problems for you. -You still need to interpret and understand these standard Oracle -metrics yourself --- Author: Tanel Poder (tanel@tanelpoder.com) -- Copyright: (c) Tanel Poder - http://blog.tanelpoder.com - All rights reserv ed. --- Disclaimer: This script is provided "as is", so no warranties or guarantees are -made about its correctness, reliability and safety. Use it at yo ur -own risk! --- License: 1) You may use this script for your (or your businesses) purpose s for free -2) You may modify this script as you like for your own (or your businesses) purpose, -but you must always leave this script header (the entire comm ent section), including the

-author, copyright and license sections as the first thing in the beginning of this file -3) You may NOT publish or distribute this script or any variatio n of it PUBLICLY -(including, but not limited to uploading it to your public we bsite or ftp server), -instead just link to its location in blog.tanelpoder.com -4) You may distribute this script INTERNALLY in your company, fo r internal use only, -for example when building a standard DBA toolset to be deploy ed to all -servers or DBA workstations ---- Thanks to: Adrian Billington, Jamey Johnston, Marcus Mönnig, Hans-Peter Sloot -and Ronald Rood for bugfixes, additions and improvements ----------------------------------------------------------------------------------- The Session Snapper v4.09 BETA ( USE AT YOUR OWN RISK !!! ) -- (c) Tanel Poder ( http://blog.tanelpoder.com ) ---+-----=====O=== Welcome to The Session Snapper! (Yes, you are looking at a cheap ASCII -- / imitation of a fish and a fishing rod. -- | Nevertheless the PL/SQL c ode below the -- | fish itself should be hel pful for quick -- | catching of relevant Orac le performance -- | information. -- | So I wish you happy... um ... snapping? -- | ) -- | ...... -- | iittii,,.... -- ¿ iiffffjjjjtttt,, -..;;ttffLLLLffLLLLLLffjjtt;;.. -..ttLLGGGGGGLLffLLLLLLLLLLLLLLffjjii,, ..ii ,, -ffGGffLLLLLLjjttjjjjjjjjffLLLLLLLLLLjjii.. ..iijj;; .... -ffGGLLiittjjttttttiittttttttttffLLLLLLGGffii.. ;;LLLLii;; ;;.. -ffEEGGffiittiittttttttttiiiiiiiittjjjjffLLGGLLii.. iiLLLLLLttiiii ,, -;;ffDDLLiiiitt,,ttttttttttttiiiiiiiijjjjjjffLLLLffttiiiiffLLGGLLjjtttt;; .. -..ttttjjiitt,,iiiiiittttttttjjjjttttttttjjjjttttjjttttjjjjffLLDDGGLLttii.. -iittiitttt, ;;iittttttttjjjjjjjjjjttjjjjjjffffffjjjjjjjjjjLLDDGGLLtt;;.. -jjjjttttii:. ..iiiiffLLGGLLLLLLLLffffffLLLLLLLLLLLLLLLLffffffLLLLLLfftt,, -iittttii,,;;,,ttiiiiLLLLffffffjjffffLLLLLLLLffLLffjjttttttttttjjjjffjjii.. -,,iiiiiiiiiittttttiiiiiiiiiijjffffLLLLLLLLffLLffttttttii;;;;iiiitttttttt;; .. -..iittttttffffttttiiiiiiiiiittttffjjjjffffffffttiittii:: ....,,;;iittii ;; -..;;iittttttttttttttttiiiiiittttttttttjjjjjjtttttt;; ..;;ii

;;.. -..;;;;iittttttjjttiittttttttttttttjjttttttttii.. .. .. -....;;;;ttjjttttiiiiii;;;;;;iittttiiii.. -..;;ttttii;;.... ..;;;;.... -..iiii;;.. -..;;,, -.... ---- Usage: --snapper.sql <ash[1-3]|stats|all>[,out][,trace][,pagesize=X][,gather=[s][ t][w][l][e][b][a]]> <seconds_in_snap> <snapshot_count> <sid(s)_to_snap> --ash - sample session activity ASH style, waits and SQL_IDs from gv$session and -print a TOP SQL/wait report from these samples (this is t he default from -Snapper 3.0). The columns chosen for TOP calculation are defined in CONFIG -section below. --ash=sql_id+event+wait_class -- the above example illustrates that you can also specify t he gv$session -columns for TOP report yourself. The above example will s how a TOP -activity report grouped by SQL_ID + EVENT + WAIT_CLASS -Note that the columns are separated by a "+" sign (as com ma is a snapper -parameter separator, not ASH column separator) --ash1 -ash2 -ash3 - in addition to "ash" report you can have 3 more reported during the same -snapper sampling snapshot. Just include ash1=col1+col2,as h2=col3+col4,... -parameters if you want multiple TOP reports per Snapper s napshot --stats - sample gv$sesstat,gv$sess_time_model,gv$session_event per formance counters -and report how much these stats increased (deltas) during Snapper run -all - report both ASH and stats sections --out - use dbms_output.put_line() for output. output will be see n only when -Snapper run completes due to dbms_output limitations. Thi s is the default. -trace - write output to server process tracefile -(you must have execute permission on sys.dbms_system.ksdw rt() for that, -you can use both out and trace parameters together if yo u like ) --pagesize - display header lines after X snapshots. if pagesize=0 don 't display

-any headers. pagesize=-1 will display a terse header only once --gather - if omitted, gathers s,t,w statistics (see below) -- if specified, then gather following: --Session-level stats: -s - Session Statistics from gv$sesstat -t - Session Time model info from gv$sess_time_model -w - Session Wait statistics from gv$session_event an d gv$session_wait --Instance-level stats: -l - instance Latch get statistics ( gets + immediate _gets ) -e - instance Enqueue lock get statistics -b - buffer get Where statistics -- useful in version s up to 10.2.x -a - All above --sinclude - if specified, then show only GV$SESSTAT stats which match the -LIKE pattern of sinclude (REGEXP_LIKE in 10g+) -linclude - if specified, then show only GV$LATCH latch stats which m atch the -LIKE pattern of linclude (REGEXP_LIKE in 10g+) -tinclude - if specified, then show only GV$SESS_TIME_MODEL stats whi ch match the -LIKE pattern of tinclude (REGEXP_LIKE in 10g+) -winclude - if specified, then show only GV$SESSION_EVENT wait stats which match the -LIKE pattern of winclude (REGEXP_LIKE in 10g+) --you can combine above parameters in any order, separate them by comm as -!!!don't use spaces as otherwise they are treated as next parameters by sqlplus !!! -!!!if you want to use spaces, enclose the whole sqlplus parameter in doublequotes !!! --<seconds_in_snap> - the number of seconds between taking snapshots -<snapshot_count> - the number of snapshots to take ( maximum value is p ower(2,31)-1 ) --<sids_to_snap> can be either one sessionid, multiple sessionids separate d by -commas or a SQL statement which returns a list of SIDs (if you need spac es -in that parameter text, enclose it in double quotes). --if you want to snap ALL sids, use "all" as value for -<sids_to_snap> parameter --alternatively you can used "select sid from gv$session" as value for <si ds_to_snap> -parameter to capture all SIDs. you can write any query (with multiple an d/or) -conditions to specify complex rules for capturing only the SIDs you want --starting from version 3.0 there are further session_id selection options

available in -instead of sid p> parameter: --sid=123 -user=tanel nsitive) --

you can write such expressions for snapper's <sids_to_sna -- take sid 123 only (the same as just writing 123) -- take all sessions where username is 'tanel' (case inse -- this is the same as writing following subquery for the

--- <sids_to_snap> parameter: -select sid from gv$session where lower(username) l ike lower('tanel') --user=tanel% -- take all sessions where username begins with 'tanel%' (case insensitive) --- the = means actually LIKE in SQL terms in this script --spid=1234 -- all these 3 parameters do the same thing: -ospid=1234 -- they look up the sessions(s) where the processes OS PI D=1234 -pid=1234 -- this is useful for quickly looking up what some OS pro cess is doing --- if it consumes too much of some resource -qc=123 -qcsid=123 -- show query coordinator and all PX slave sessions --program=sqlplus% -- the following examples filter by correspondin g gv$session coulmns -machine=linux01 -- machine -osuser=oracle -- os username -module=HR -- module -"action=Find Order" -- note the quotes because there is a space insi de the parameter --- value -client_id=tanelpoder -- show only sessions where client_identifier is set to tanelpoder --- this is very useful in cases with (properly i nstrumented) --- connection pools ---Note that if you want to change some "advanced" snapper configuration pa rameters -or default values then search for CONFIG in this file to see configurabl e -variable section ---- Examples: -NB! Read the online examples, these are more detailed and list script ou tput too! --http://tech.e2sn.com/oracle-scripts-and-tools/session-snapper --@snapper ash,stats 1 1 515 -(Output one 1-second snapshot of session 515 using dbms_output and exit -Wait, gv$sesstat and gv$sess_time_model statistics are reported by defa ult -Starting from V3 the ASH style session activity report is shown as well )

gather=w 1 1 515 -(Output one 1-second snapshot of session 515 using dbms_output and exit -only Wait event statistics are reported. thus it may report bogus -statistics for such sessions.x extended syntax: @snapper <options> <"beg in"|"end"|sleep#> <"snap_name"|snap_count> <sid>) define snapper_options="&1" define snapper_sleep="&2" define snapper_count="&3" define snapper_sid="&4" -.different Oracle versions.2. no ASH) --@snapper ash.--@snapper stats.statements might not compile if not adjusted properly.The following code is required for making this script "dynamic" as due to -.313 -(Write 90 10-second snapshots into tracefile for session IDs 117.plsql_object_id columns available in v$session (from 10. writ e -output to both dbms_output and tracefile) --.ash.Notes: --Snapper does not currently detect if a session with given SID has -ended and been recreated between snapshots. do not print any headers) --@snapper trace. -loop (almost) forever ) --@snapper out.gather=st 1 1 515 -(Output one 1-second snapshot of session 515 using dbms_output and exit -only gv$sesstat and gv$sess_Time_model statistics are gathered + ASH) --@snapper trace.313 -all statistics are reported. define _IF_ORA11_OR_HIGHER="--" define _IF_LOWER_THAN_ORA11="--" define _IF_DBMS_SYSTEM_ACCESSIBLE="/* dbms_system is not accessible" -.3) define _YES_PLSQL_OBJ_ID="--" define _NO_PLSQL_OBJ_ID="" ./*dummy*/ -.set termout on serveroutput on -.gather=stw.ash 900 999999999 "select sid from v$session" -(Take a snapshot of ALL sessions every 15 minutes and write the output t o trace.0.trace 300 12 "select sid from v$session where username='APP S'" -(Take 12 5-minute snapshots of all sessions belonging to APPS user.210. The check and warning for that will be -implemented in a future version. script parameters or granted privileges some -.pagesize=0 10 90 117. --------------------------------------------------------------------------------set termout off tab off verify off linesize 999 trimspool on trimout on null "" --debug: -.210.Get parameters (future snapper v4.this "dummy" is here just for avoiding VIM syntax highlighter go ing crazy due to previous line define _IF_X_ACCESSIBLE="--" -.

number_table.number_table.number_table. not just a single SID) -.number_table.dbms_describe.dbms_describe.sid_filter and inst_filter are the new RAC gv$ friendly way to filter session s in Snapper v4 def sid_filter="/**/" def inst_filter="/**/" col sid_filter &noprint new_value sid_filter col inst_filter &noprint new_value inst_filter -.number_table.set the noprint's value to "noprint" if you don't want these temporary variab les to show up in a sqlplus spool file DEF noprint="" col snapper_ora11higher &noprint new_value _IF_ORA11_OR_HIGHER col snapper_ora11lower &noprint new_value _IF_LOWER_THAN_ORA11 col dbms_system_accessible &noprint new_value _IF_DBMS_SYSTEM_ACCESSIBLE col x_accessible &noprint new_value _IF_X_ACCESSIBLE col no_plsql_obj_id &noprint new_value _NO_PLSQL_OBJ_ID col yes_plsql_obj_id &noprint new_value _YES_PLSQL_OBJ_ID col no_blk_inst &noprint new_value _NO_BLK_INST col yes_blk_inst &noprint new_value _YES_BLK_INST col manual_snapshot &noprint new_value _MANUAL_SNAPSHOT col use_dbms_lock &noprint new_value _USE_DBMS_LOCK col snapper_sid &noprint new_value snapper_sid -.2) define _YES_BLK_INST="--" define _NO_BLK_INST="" -. sys. sys. sys.dbms_describe.number_table.this is here for a reason -. sys.-.dbms_describe. sys.number_table.dbms_describe. sys. sys. sys.dbms_describe.number_table.number_table.im extracting the first word of the snapper_sid (if its a complex expression. sys.dbms_describe. precompute var v var x var sid_filter var inst_filter and determine stuff varchar2(100) varchar2(10) varchar2(4000) varchar2(4000) -.blocking_instance available in v$session (from 10. sys.dbms_describe.number_table.dbms_describe. . sys.dbms_describe.by relying on how DEF and & assignment treat spaces in strings def ssid_begin=&snapper_sid declare o p l a dty def inout len prec scal rad spa tmp sys.number_table.dbms_describe. number.snapper v4 manual before/after snapshotting define _MANUAL_SNAPSHOT="--" define _USE_DBMS_LOCK="" -.varchar2_table.dbms_describe.initialize.

when trim(lower('&ssid_begin')) like 'module=%' then lv_sid_filter := 'lower(module) like ''' ||get_filter('&ssid_begin')||''''. begin if str like '%@%' then --dbms_output.instr(str.'=')+1))). begin -.*)'. varchar2(4000). --dbms_output. end get_filter. when regexp_instr('&ssid_begin'. '\2') end case.'@') = 0 then lv_inst_filter := '/* inst_filter */ s.inst_id=USERENV(''Instance'')'. when trim(lower('&ssid_begin')) like 'action=%' then lv_sid_filter := 'lower(action) like ''' ||get_filter('&ssid_begin')||''''.*)'. 'sid='. '\1'))). else --dbms_output.inst_id=USERENV(''Instance'') '. -. else lv_inst_filter := 's.instr(str. '\2').compute inst_filter case when regexp_instr('&ssid_begin'. when trim(lower('&ssid_begin')) like 'service=%' then lv_sid_filter := 'lower(service_name) like ''' ||get_filter('&ssid_begin')||''''. ret := lower(trim(substr(str. when trim(lower('&ssid_begin')) like 'program=%' then lv_sid_filter := 'lower(program) like ''' ||get_filter('&ssid_begin')||''''.inst_id = ' || regexp_replace('&ssid_begin'.put_line('get_filter = ' || ret).lv_sid_filter lv_inst_filter varchar2(4000). '^(. when trim(lower('&ssid_begin')) like 'username=%' then lv_sid_filter := 'lower(username) like ''' ||get_filter('&ssid_begin')||''''. function get_filter(str in varchar2) return varchar2 is ret varchar2(1000).+)@(\d+)(. when trim(lower('&ssid_begin')) like 'osuser=%' then lv_sid_filter := 'lower(osuser) like ''' ||get_filter('&ssid_begin')||''''. end if.'@\d+') > 0 then regexp_replace(snap per_sid.*)'.put_line('get_filter:2 str= '||str).''))||')'. --when regexp_instr('&ssid_begin'. '^(. --||trim(replace('&ssid_begin'.'=')+1).put_line('get_filter:1 str= '||str). when trim(lower('&ssid_begin')) like 'machine=%' then lv_sid_filter := 'lower(machine) like ''' ||get_filter('&ssid_begin')||''''. when regexp_instr('&ssid_begin'.compute sid_filter case when trim(lower('&ssid_begin')) like 'sid=%' then lv_sid_filter := 's.+)@(\d+)(.'@\d+') > 0 then lv_inst_filter := 's. '^(.'@\*') > 0 or '&ssid_begin' like '(%' th en lv_inst_filter := '/* inst_filter */ 1=1'. when trim(lower('&ssid_begin')) like 'client_id=%' then lv_sid_filter . '^ (.+)@\d+'. return ret. when trim(lower('&ssid_begin')) like 'user=%' then lv_sid_filter := 'lower(username) like ''' ||get_filter('&ssid_begin')||''''. ret := lower(trim(regexp_replace(substr(str.sid in ('||get_filter('&ssid_begin')||')'.+)@([ [:digit:]\*]+)(. '\1') || ' AND inst_id = ' || regexp_replace(snapper_sid.

lv_sid_filter := q'{(s.:= 'lower(client_identifier) like '''||get_filter('&ssid_begin')||''''. end case.sid) in (select /*+ NO_UNNEST */ inst_id.even if its not executable by us (thanks to o7_dictionary_accessibility=f alse) begin execute immediate 'select count(*) from x$kcbwh where rownum = 1' into t mp.sid from gv$px_sessi on where qcsid in ('||get_filter('&ssid_begin')||'))'. .sid) in (&snapper_s id)}'.sid in ('||get_filter('&ssid_begin')||')'. 'select /*+ unnest */ '. lv_inst_filter := '1=1'. when trim(lower('&ssid_begin')) like 'all%' then lv_sid_filter := '1=1'.sid) in ('||regexp_replace(replace(q'{&snapper_sid}'.paddr) in (select /*+ NO_UNNEST */ inst_id.inst_id.addr from gv$process wh ere spid in ('||get_filter('&ssid_begin')||'))'. when trim(lower('&ssid_begin')) like 'ckpt%' then lv_sid_filter := 'program like ''%(CKPT)%'''.ksdwrt is accessible to us -. when trim(lower('&ssid_begin')) like 'ospid=%' then lv_sid_filter := '(s.s.s. when trim(lower('&ssid_begin')) like 'bg%' then lv_sid_filter := 'type=''BACKGROUND'''.s.inst_id.inst_id. --lv _sid_filter := '/* sid_filter_else_cond */ s.paddr) in (select /*+ UNNEST */ inst_id.'1=1'. lv_inst_filter := '1=1'. else lv_sid_filter := '/* sid_filter_else_cond */ s.inst_id. when trim(lower('&ssid_begin')) like 'qc=%' then lv_sid_filter := '(s.'1=1'. when trim(lower('&ssid_begin')) like 'spid=%' then lv_sid_filter := '(s.inst_id. -.dbms_describe is required as all_procedures/all_objects may show this obj ect -. :inst_filter := lv_inst_filter.s. when trim(lower('&ssid_begin')) like 'pmon%' then lv_sid_filter := 'program like ''%(PMON)%'''.this block determines whether dbms_system.addr from gv$process wh ere spid in ('||get_filter('&ssid_begin')||'))'. 1. when trim(lower('&ssid_begin')) like 'select%' then /*lv_inst_filter := '/* inst_filter2 1=1'. '^select '. :sid_filter := lv_inst_filter||' and '||lv_sid_filter.sid) in (select /*+ NO_UNNEST */ inst_id. when trim(lower('&ssid_begin')) like 'fg%' then lv_sid_filter := 'type=''USER'''.s.inst_id. when trim(lower('&ssid_begin')) like 'smon%' then lv_sid_filter := 'program like ''%(SMON)%'''. when trim(lower('&ssid_begin')) like '(%' then lv_inst_filter : = '/* inst_filter2 */ 1=1'.inst_id.sid from gv$px_sessi on where qcsid in ('||get_filter('&ssid_begin')||'))'. */ lv_sid_filter := q'{(s.s.sid) in (&snapper_sid)'.inst_id.addr from gv$process where spid in ('||get_filter('&ssid_begin')||'))'. when trim(lower('&ssid_begin')) like 'dbwr%' then lv_sid_filter := 'program like ''%(DBW%)%'''. -. --when trim(lower('&ssid_begin')) like 'select%' then lv_sid_filter := '(s. -. --when trim(lower('&ssid_begin')) like 'with%' then lv_sid_filter := '(s. when trim(lower('&ssid_begin')) like 'lgwr%' then lv_sid_filter := 'program like ''%(LGWR)%'''.'1=1'.s.s.sid in (&ssid_begin)'.inst_id. 'i')||')'.'''''') . when trim(lower('&ssid_begin')) like 'pid=%' then lv_sid_filter := '(s. lv_inst_filter := '1=1'.s.paddr) in (select /*+ UNNEST */ inst_id. 1.''. -. when trim(lower('&ssid_begin')) like 'qcsid=%' then lv_sid_filter := '(s.sid) in (&snapp er_sid)}'.

'Release ')+8. p. 'Release ')+8. '/* dbms_system is not accessible') dbms_system_accessible. :sid_filter sid_filter.2) >= '11' then '' else '--' end snapper_ora11higher.3' then '--' else '' end no_plsql _obj_id. rad. '') snappe r_ora10lower. o. '--'.end%' or lower('&snapper _options') like 'end%' then '' else '--' end manual_snapshot.2). nvl(:v.0. 'Release ')+8. instr(substr(banner.'Release ')+8).' ') ) >= '10. instr(banner. case when lower('&snapper_options') like '%. so dont comment any lines out exception when others then null.' ') ) >= '10.') banner from v$version where rownum = 1 ) select decode(substr(banner. instr(banner.dbms_describe. instr(banner. .'Release ')+8). / -.i nstr(banner. instr(substr(banner. case when substr( banner.begin%' or lower('&snapper_optio ns') like 'begin%' or lower('&snapper_options') like '%. ''.x$ tables are accessible.dbms_system is accessible'. end. instr(banner. instr(banner. '1'. sys.describe_procedure( 'DBMS_SYSTEM. instr(banner. spa ). 'Release ')+8.'Release ')+8). inout. case when substr(banner. 'Release ')+8.'09.i nstr(banner.2' then '' else '--' end yes_blk_ inst. '09'.KSDWRT'. 'Release ')+8. null. case when substr( banner. instr(substr(banner. -. decode(substr(banner.begin%' or lower('&snapper_optio ns') like 'begin%' or lower('&snapper_options') like '%. dty. prec.3' then '' else '--' end yes_plsq l_obj_id. nvl(:x. case when substr(banner. def.1). instr(banner. end. instr(banner.i nstr(banner.'. instr(banner.as sys.this query populates some sqlplus variables required for dynamic compilation used below with mod_banner as ( select replace(banner.:x:= ' '. null.'9. ''. 'Release ')+8. instr(substr(banner. '09'. '--') snapp er_ora10higher. case when lower('&snapper_options') like '%. 'Release ')+8.we never get to following statement if dbms_system is not accessible -. 'Release ')+8. -.dbms_describe will raise an exception :v:= '-. exception when others then null. '--') x_accessible. scal.' ') ) >= '10. decode(substr(banner. case when substr( banner.' ') ) >= '10.2.2.end%' or lower('&snapper _options') like 'end%' then '--' else '' end use_dbms_lock.i nstr(banner.0.'Release ')+8). '--') snapp er_ora9.2). len. case when substr( banner. l. a.2' then '--' else '' end no_blk_i nst.2) < '11' then '' else '--' end snapper_ora11lower.

tmp_varchar2 varchar2(1000).misc . statistic# number. type srec is record (ts timestamp.type. taking &snapper_cou nt snapshots. -.' ) return varchar2. type stab is table of srec index by pls_integer.:inst_filter inst_filter from mod_banner / set termout on serveroutput on size 1000000 format wrapped prompt Sampling SID &4 with interval &snapper_sleep seconds. type snrec is record (stype varchar2(4). type ltab is table of srec index by varchar2(100). variable declarations -. p_stype in varchar2 default 'STAT'. procedure fout. event_count number ). p_grouplen in number default 3 ) return varchar2.let the Snapping start!!! -. statistic# number. function tptformat( p_num in number. s2 stab. function getopt( p_parvalues in varchar2. type sntab_reverse is table of snrec index by varchar2(100). -.forward declarations procedure output(p_txt in varchar2).. -.1. inst_id number. sn_tmp sntab. p_extract in varchar2. p_delim in varchar2 default '. value number. sn sntab. -.0) := power(2.31) . p_precision in number default 2. l1 ltab.used for loo king up stat id from stat name sn_reverse sntab_reverse. name varchar2(10 0)).Snapper start -. l2 ltab. stype varchar2(4).main() declare -.lookup tab for various average calculation s1 stab. sid nu mber.. type sntab is table of snrec index by pls_integer. constant. p_base in number default 10.trick for holding 32bit UNSIGNED event and stat_ids in 32bit SIGNED PLS_I NTEGER pls_adjust constant number(10. -.

g_mysid i number. b number.function get_useful_average(c in srec /* curr_metric */. missing_values_s1 number := 0. varchar2(1000). lv_gather varchar2(1000). varchar2(1000).dbms_debug_vc2coll is a built-in collection present in every oracle db g_ash sys. g_count_statname number. d2 timestamp(6). type sestab is table of gv$session%rowtype index by varchar2(20). number := 0. g_snap2 sys. lv_ash lv_stats gather_stats gather_ash g_snap_begin g_snap_end varchar2(1000). -.dbms_debug_vc2coll.dbms_debug_vc2coll(). g_count_eventname number. changed_values number.dbms_debug_vc2coll. number := 0. missing_values_s2 number := 0. delta number. ash_date2 date. sestab. g_empty_ses_hash_tab ses_hash_tab.dbms_debug_vc2coll := new sys. -. type tmp_sestab is table of gv$session%rowtype index by pls_integer. -. g_ash_samples_taken number := 0. c number. g_sessions g_empty_sessions lue type ses_hash_tab is table of hc_tab index by pls_integer.index is sql hash va .dbms_debug_vc2coll(). p in srec /* all_pr ev_metrics */) return varchar2. number. g_empty_ash sys. evcnt number. pagesize number:=99999999999999. -. g_snap1 sys. type hc_tab is table of number index by pls_integer. varchar2(1000). lv_curr_sid number := 0. ash_date1 date. sestab.used for determining whether to print an e mpty line between session stats d1 timestamp(6).dbms_debug_vc2coll := new sys. disappeared_sid number := 0. gv_header_string varchar2(1000). lv_data_string varchar2(1000).index is SID g_ses_hash_tab ses_hash_tab. a number.

12.human readable delta normalized to per sec ond output_percent number := 1.wait event count output_eventavg number := 1.percent of total time/samples output_eventcnt number := 1.statistic type (WAIT. -.is_cluster_database = TRU E THEN 1 ELSE 0 END. 6.statistic name output_delta number := 1.wait event count output_eventcnt_s number := 1.raw delta normalized to per second output_hdelta number := 0. 10. 12.column widths in ASH report output w_inst_id number := w_sid number := w_username number := w_machine number := w_terminal number := w_program number := w_event number := w_wait_class number := w_state number := w_p1 number := w_p2 number := w_p3 number := w_row_wait_obj# number := w_row_wait_file# number := w_row_wait_block# number := w_row_wait_row# number := w_blocking_session_status number := w_blocking_instance number := w_blocking_session number := w_sql_hash_value number := w_sql_id number := w_sql_child_number number := 4. 25. -. 20.LATG. -. 12. 15. 20. -. 9. 20. 35. -. -.raw delta output_delta_s number := 0. -.this sets what g_ash_columns vent + wait_class'. -.v$session. -. -. -. -.inst output_sid number := CASE WHEN dbms_utility. -. 15.inst_id and sid together output_time number := 0. -.average wait duration output_pcthist number := 1.seconds in snapshot (shown in footer of ea ch snapshot too) output_stype number := 1.7 + .percent of total visual bar (histogram) -Histograms seem to work for me on 9. -. 20.human readable delta output_hdelta_s number := 1.0.-. 10.is_cluster_database = TRU E THEN 0 ELSE 1 END.just sid output_inst_sid number := CASE WHEN dbms_utility.ENQG.1=true 0=false output_username number := 1. -.2.. 6.username output_inst number := 0. .JBJ2) -. .time of snapshot start output_seconds number := 0. -. 8. -.CONFIGURABLE STUFF --.STAT. are the default ash sample TOP reporting group by columns varchar2(1000) := 'inst_id + sql_id + sql_child_number + e varchar2(1000) := 'inst_id + event + p1 + wait_class'. 20. 20. 6. 15. g_ash_columns1 g_ash_columns2 m'.) output_sname number := 1.TIME. g_ash_columns3 ogram_id + sql_id'. varchar2(1000) := 'inst_id + sid + user + machine + progra varchar2(1000) := 'inst_id + plsql_object_id + plsql_subpr -.output column configuration output_header number := 0..

s_username constant number := 3 . c_sid constant number := power(2. s_row_wait_obj# constant number := 13 . s_row_wait_block# constant number := 15 . s_row_wait_file# constant number := 14 . s_machine ). s_program constant number := 6 . s_p1 constant number := 10 . s_state constant number := 9 . s_service_name constant number := 30 .constants for ash collection reporting. s_event constant number := 7 . s_sid ). 10. s_p3 constant number := 12 . s_username ). s_client_identifier constant number := 29 . 10. 10. c_username constant number := power(2.END CONFIGURABLE STUFF -- number number number number number number number number := := := := := := := := 10. c_terminal constant number := power(2. which columns to show in report c_inst_id constant number := power(2. s_sid constant number := 2 . -. s_blocking_session constant number := 19 . . -. 25. s_sql_id constant number := 21 . s_inst_id ). s_program ). s_row_wait_row# constant number := 16 . s_terminal constant number := 5 . 25. c_event constant number := power(2. s_module constant number := 27 . s_plsql_object_id constant number := 25 . s_machine constant number := 4 . c_program constant number := power(2. s_sql_child_number constant number := 22 . s_plsql_subprogram_id constant number := 26 . s_blocking_instance constant number := 18 . s_sql_hash_value constant number := 20 . s_terminal ). s_plsql_entry_subprogram_id constant number := 24 . s_wait_class constant number := 8 . s_plsql_entry_object_id constant number := 23 . c_machine constant number := power(2. s_event ). 25.constants for ash collection extraction from the vc2 collection s_inst_id constant number := 1 . number := 7. s_p2 constant number := 11 . s_blocking_session_status constant number := 17 . s_action constant number := 28 . 25.w_plsql_entry_object_id w_plsql_entry_subprogram_id w_plsql_object_id w_plsql_subprogram_id w_module w_action w_client_identifier w_service_name w_activity_pct -.

s_row_wait_row# constant number := power(2. s_blocking_sessio constant number := power(2. c_plsql_object_id ). c_sql_id ). s_blocking_sessio constant number := power(2. s_row_wait_file# constant number := power(2. s_sql_hash_value constant number := power(2. s_state constant number := power(2.c_wait_class ). . constant number := power(2. c_blocking_instance ce ). s_plsql_entry_sub constant number := power(2. c_blocking_session_status n_status ). c_row_wait_obj# ). c_p2 ). s_row_wait_obj# constant number := power(2. s_client_identifi constant number := power(2. s_p2 constant number := power(2. c_action ). c_sql_hash_value ). s_row_wait_block# constant number := power(2. s_p3 constant number := power(2. s_plsql_entry_obj constant number := power(2. s_sql_id constant number := power(2. s_plsql_subprogra constant number := power(2.proc for outputting data to trace or dbms_output ---------------------------------------------------*/ procedure output(p_txt in varchar2) is begin if (getopt('&snapper_options'. c_plsql_subprogram_id m_id ). 'out') is null and getopt('&snapper_optio ns'. c_sql_child_number r ). 'trace') is null) then dbms_output. c_state ). s_p1 constant number := power(2. c_plsql_entry_object_id ect_id ). c_row_wait_file# ). c_row_wait_row# ). c_p3 ). c_plsql_entry_subprogram_id program_id). c_blocking_session n ). c_row_wait_block# ). c_p1 ). s_service_name /*---------------------------------------------------. s_plsql_object_id constant number := power(2. c_service_name ). s_module constant number := power(2.put_line(p_txt). s_sql_child_numbe constant number := power(2. 'out') is not null) or (getopt('&snapper_options'. s_wait_class constant number := power(2. c_module ). s_blocking_instan constant number := power(2. c_client_identifier er ). s_action constant number := power(2.

In fout().co unt='||s1.statistic# ).*/ end.ksdfls. --output (CASE WHEN output_eventavg = 1 THEN CASE WHEN s2(b). s2(b). instr(g_sessions(gsid).program.statistic #). --output( 'DEBUG. 10.stype).'||trim(to_char(s2(b). substr(g_se ssions(gsid). if output_username = 1 then begin l_output_username := nvl( g_sessions(gsid).inst_id))||'.inst_id. s1(a)) E ND END). gsid := trim(to_char(s2(b). end if. ' ')||' average wait' ELSE get_useful_average(s2(b).dbms_system. end if. end get_seconds.statistic #='||s2(b).stype='WAIT' then output( 'DEBUG WAIT ' || sn(s2(b).name || ' ' || delta ). --output('after'). gsid varchar2(20).dbms_system.count||' s2.The block below is a sqlplus trick for conditionally commenting out P L/SQL code &_IF_DBMS_SYSTEM_ACCESSIBLE if getopt('&snapper_options'. -. '99 . utilizing global vars ---------------------------------------------------*/ procedure fout is l_output_username VARCHAR2(100). output( CASE WHEN output_header || CASE WHEN output_inst = 1 THEN 'SID= ' END = 1 THEN to_char(s2(b). a='||to_char(a)||' b='||to_char(b)||' s1. --output( 'DEBUG.program.count).sid)). -.DEBUG --output('before'). Entering fout(). p_txt). exception when no_data_found then l_output_username := 'error'. when others then raise. b='||to_char(b)||' sn(s2(b). begin --if s2(b).count||' s2.function for converting interval datatype to microseconds ---------------------------------------------------*/ function get_seconds(i interval day to second) return number as begin return to_number(extract(second from i)) + to_number(extract(minute from i)) * 60 + to_number(extract(hour from i)) * 60 * 60 + to_number(extract(day from i)) * 60 * 60 * 24.'(')) ). sys.count='||s2. /*---------------------------------------------------. end.output /*---------------------------------------------------.proc for outputting data. end if. 'trace') is not null then sys.end if. -.ksdwrt(1.count='||s2.stype IN ('WAIT') THEN lpad(tptformat(delta / CASE WHEN evcnt = 0 THEN 1 ELSE evcnt END. -.username.

name = 'DB CPU' THEN '@' ELSE '#' END).stype). '9999. /*---------------------------------------------------.stype IN ('WAIT') THEN 'W' WHEN sn(s2(b).sid.9')||'%' ELSE ' ' END END ||'. val1 number.99')||'. CASE WHEN s2( b). ' END || CASE WHEN output_username = 1 THEN rpad(CASE s2(b). ' ')||'.l1. ' END || CASE WHEN output_percent = 1 THEN CASE WHEN s2(b).stype). ' ')||' average wait' ELSE get_useful_average(s2(b).stype IN ( 'WAIT') THEN lpad(tptformat((evcnt / case get_seconds(d2-d1) when 0 then &snappe r_sleep else get_seconds(d2-d1) end ).'WAIT') THEN to_char(delta/CASE get_seconds(d2-d1) WHEN 0 THEN &snapper_s leep ELSE get_seconds(d2-d1) END / 10000. ' END || CASE WHEN output_sid = 1 THEN to_char(s2(b).stype IN ( 'TIME'.'99999') ||' '||lpad('@'||trim(to_char(s2(b). name. ' END || CASE WHEN output_hdelta_s = 1 THEN lpad(tptformat(delta/(case get_seconds(d2-d1) when 0 then &snapper_sleep else get_seconds(d2-d1) end ).stype||'. ' E ND || CASE WHEN output_stype = 1 THEN s2(b). 10.' ')||']' ELSE ' ' END END||'. s2 (b). val2 number. ' END || CASE WHEN output_inst_sid = 1 THEN to_char(s2(b). ' ') END. ' || CASE WHEN output_pcthist = 1 THEN CASE WHEN s2(b).inst_id. 10.11.'999999999' )||'. ' END || CASE WHEN output_sname = 1 THEN rpad(sn(s2(b). ' || CASE WHEN output_eventcnt_s = 1 THEN CASE WHEN s2(b). 10.value) ---------------------------------------------------*/ function get_delta(metric_id in varchar2) return number is rec1 srec. ' END || CASE WHEN output_delta_s = 1 THEN to_char(delta/(case get_se conds(d2-d1) when 0 then &snapper_sleep else get_seconds(d2-d1) end). .3)||'.statistic#). 10)||'.stype IN ( 'WAIT') THEN to_char(evcnt. s1(a)) END END ). ' ') ELSE ' ' END END||'. 'STAT' ). '9999999')||'.lookup stat delta helper calculator (l2. 58. 'YYYYMMDD HH24 :MI:SS')||'. s2(b ). s 2(b).stype IN ( 'WAIT') THEN lpad(tptformat(delta / CASE WHEN evcnt = 0 THEN 1 ELSE evcnt END.stype IN ( 'TIME'. ' || CASE WHEN output_eventcnt = 1 THEN CASE WHEN s2(b).value . ' END || CASE WHEN output_hdelta = 1 THEN lpad(tptformat(delta. ' || CASE WHEN output_eventavg = 1 THEN CASE WHEN s2(b).sid.'WAIT') THEN rpad(rpad('['. rec2 srec. ' ')||'.'999999' )||'. ' ')||'. 10. '99')). '9999999999 99')||'. ' END || CASE WHEN output_time = 1 THEN to_char(d1. '99999999') ELSE ' ' END END||'.stype). end.statistic#).sid WHEN 1 THEN ' ' ELSE NVL(l_output_username. ceil(round(delta/CASE get_seconds(d2-d1) WHEN 0 THEN &snapper_sleep ELSE get_seconds(d2-d1) END / 100000. ' END || CASE WHEN output_seconds = 1 THEN to_char(case get_seconds(d 2-d1) when 0 then &snapper_sleep else get_seconds(d2-d1) end. ' END || CASE WHEN output_delta = 1 THEN to_char(delta.1))+1.

--output('tmp_delta '||c.name. if not specified then get current one ---------------------------------------------------*/ function gd(c in srec.inst_id))||'.s id))||'.'||trim(to_char(c.metric_name begin case when mt = 'STAT' then case when mn = 'bytes sent via SQL*Net to client' then ret := l . return d. -.sid))||'.delta helper function for convenience .return get_delta(str). else begin str := trim(metric_type)||'.stype||' '||tmp_delta).'||metric_name). metric_type in varchar2 DEFAULT NULL.NVL(val1. end get_delta. begin val2 := l2(metric_id). exception when no_data_found then val1 := 0.stype||'.d number.'||trim(to_char(c. -. 0).'||trim(to_char(sn_reverse(metric_type||'.function for calculating useful averages and ratios between metrics ---------------------------------------------------*/ function get_useful_average(c in srec /* curr_metric */. statistic#)).'||trim(to_char(c. begin begin val1 := l1(metric_id). end.'||trim(to_char(c.it allows to specify any metric de lta. end. end if.'999999999999999999999999')). p in srec /* all_pr ev_metrics */) return varchar2 is ret varchar2(1000). tmp_delta number.value. /*---------------------------------------------------. -. mt varchar2(100) := c.statistic#. exception when no_data_found then val2 := 0. /*---------------------------------------------------. metric_name in varchar2 DEFAULT NULL) return number is str varchar2(1000). exception when no_data_found then return 0. tmp_delta := get_delta(str). begin if metric_type || metric_name is null then str := c. end.statistic#).'||tr im(to_char(c.stype. return tmp_delta.metric_type mn varchar2(100) := sn(c. end.value. d := val2 .inst_id))||'.

'class slave wait') . 'STAT'.gd(c. else ret := l pad( tptformat(gd(c) / nullif(gd(c. mt).0). 'WAIT'. 'session logical reads'). mt). 10) || ' bytes per user commit'.pad( tptformat(gd(c) / nullif(gd(c. 'IORM Scheduler Slave Idle Wait') . when mn = 'parse count (total)' then ret := l pad( tptformat(gd(c) / nullif(gd(c.0). 'rdbms ipc message') .mt=stat. 10) || ' bytes per roundtrip' . 'execute count'). 'parse count (hard)' ) . end case. mt). mt).0). 'WAIT'. 'WAIT'. 'VKRM Idle') . 'STAT'. 'WAIT'. mt).nullif(gd(c. 'WAIT'. 'WAIT'. 'user commits' ) . mn when mt = 'TIME' then -.d1)*1000000 . 'pmon timer') . mt). 'STAT'.gd(c. 10) || ' total buffer visits'. 'VKTM Init Wait for GSGA') . 'PING') . 'wait for unread message on broadcas t channel') . 'SQL*Net roundtrips to/from client') . 'STAT'.gd(c. 'STAT'. 10) || ' executions per parse'.0) * 100. 'WAIT'.gd(c. when mn = 'execute count' then ret := l pad( tptformat(gd(c) / nullif(gd(c.gd(c. when mn = 'redo size' then ret := l pad( tptformat(gd(c) / nullif(gd(c.0). 10) || ' p er execution' .gd(c. when mn = 'buffer is pinned count' then ret := l pad( tptformat(gd(c) / nullif(gd(c) + gd(c.0). when mn = 'session logical reads' then ret := l pad( tptformat(gd(c) + (gd(c.gd(c.this is ugly and wrong at the moment . 'STAT'. -. mt).0). 'STAT'. 10) || ' softparses avoided thanks to cursor cache'. when mn = 'session cursor cache hits' then ret := l pad( tptformat(gd(c) (gd(c. 'STAT'.gd(c. 'i/o slave wait') . 'buffer is pinned count' ) ).will refactor some day case when mn = 'DB time' then ret := l pad(tptformat(get_seconds(d2 . 10) || ' softparses per hardparse'. 'DB CPU'.gd(c. mt). 'SQL*Net roundtrips to/from client') .gd(c. when mn = 'bytes receive via SQL*Net from client' then ret := l pad( tptformat(gd(c) / nullif(gd(c.gd(c. 'wait for unread message on multiple broadcast channels') . 'parse count (total)' ) .gd(c. 'WAIT'. 10) || ' bytes per roundtrip' . 'TIM E') . 'KSV master wait') .gd(c) . 'WAIT'. 10) || ' % buffer gets avoided thanks to buffer pin caching'. 'WAIT'. 'WAIT'. 'WAIT'. 'parse count (total)' ) ). 'STAT'. mt). 'VKTM Logical Idle Wait') .

'WAIT'. 'WAIT'. 'WAIT'.gd(c. 'LogMiner: activate') . 'LogMiner reader: redo (idle)') .gd(c. 'LogMiner: other') .gd(c. 'WAIT'. 'SGA: MMAN sleep for component shrin k') . 'parallel recovery slave idle wait') . 'simulated log write delay') . 'WAIT'. 'WAIT'. 'WAIT'. 'LogMiner reader: log (idle)') . 'LNS ASYNC dest activation') . 'WAIT'. 'LNS ASYNC end of log') .gd(c.gd(c.gd(c. 'WAIT'.gd(c. 'WAIT'. 'LogMiner client: transaction') .gd(c. 'WAIT'.gd(c.gd(c. 'parallel recovery control message r eply') . 'WAIT'. 'GCR sleep') . 'MRP redo arrival') .gd(c.gd(c. 'DIAG idle wait') . 'parallel recovery slave next change . 'WAIT'.gd(c. 'WAIT'. 'WAIT'. 'WAIT'. 'WAIT'.gd(c. 'WAIT'.gd(c.gd(c. 'LogMiner builder: branch') .gd(c.gd(c.gd(c.gd(c. 'WAIT'. 'WAIT'.gd(c..gd(c. 'WAIT'. 'WAIT'. 'WAIT'. 'Logical Standby Apply Delay') . 'LogMiner: find session') .gd(c. 'WAIT'.gd(c. 'LogMiner: internal') . 'LogMiner: reset') . 'WAIT'.gd(c. 'ges remote message') . 'heartbeat monitor sleep') .gd(c. 'watchdog main loop') . 'LNS ASYNC archive log') . 'LogMiner preparer: idle') . 'WAIT'. 'LogMiner builder: idle') .gd(c. 'WAIT'. 'WAIT'. 'WAIT'. 'gcs remote message') .gd(c.gd(c. 'parallel recovery coordinator waits for slave cleanup') . 'LGWR real time apply sync') .

'WAIT'.gd(c. 'PX Deq: Txn Recovery Start') .gd(c. 'Space Manager: slave idle wait') . 'PX Deq: Parse Reply') .gd(c. 'WAIT'.gd(c. 'PX Deq: Metadata Update') . 'WAIT'. 'WAIT'. 'WAIT'. 'WAIT'.gd(c. 'pipe get') . 'WAIT'.gd(c.gd(c.gd(c. 'dispatcher timer') . 'WAIT'. 'WAIT'. 'WAIT'.gd(c. 'PX Deq: Index Merge Execute') . 'WAIT'. 'PX Deq: Index Merge Reply') . 'WAIT'.gd(c.gd(c. 'WAIT'.gd(c. 'WAIT'. 'WAIT'. 'shared server idle wait') .gd(c. 'WAIT'.gd(c. 'PX Deq: Txn Recovery Reply') . 'PX Idle Wait') . 'PX Deq Credit: send blkd') . 'WAIT'.gd(c.gd(c. 'PX Deq: kdcph_mai') . 'WAIT'.gd(c. 'smon timer') .gd(c.gd(c. 'WAIT'. 'PX Deq: Execute Reply') . 'JOX Jit Process Sleep') . 'fbar timer') .gd(c.gd(c.') . 'PX Deq: Table Q Sample') . 'PX Deq: kdcphc_ack') .gd(c. 'PX Deq: Index Merge Close') . 'WAIT'.gd(c. 'WAIT'. 'WAIT'. 'PX Deque wait') .gd(c. 'WAIT'. 'PX Deq Credit: need buffer') .gd(c. 'WAIT'. 'WAIT'.gd(c.gd(c.gd(c. 'WAIT'. 'PX Deq: Msg Fragment') .gd(c. 'WAIT'. 'PX Deq: Execution Msg') . 'PX Deq: Table Q Normal') . 'pool server timer') . 'WAIT'. 'PX Deq: Join ACK') . 'cmon timer') . 'jobq slave wait') . 'WAIT'.

'Streams: waiting for messages') . 'SQL*Net vector message from dblink' ) .gd(c. 'WAIT'. 'cell worker idle') . 'Streams AQ: RAC qmn coordinator idl e wait') .gd(c. 'Streams AQ: emn coordinator idle wa it') . 'Streams AQ: qmn slave idle wait') .gd(c.gd(c.gd(c.gd(c. 'WAIT'. 'WAIT'. 'WCR: replay clock') .gd(c.gd(c. 'WAIT'. 'Streams capture: waiting for archiv e log') . 'Streams AQ: waiting for time manage ment or cleanup tasks') . 'WAIT'. 'single-task message') . 'WAIT'. 'WAIT'. 'JS external job') . 'WAIT'. 'WAIT'. 'WAIT'. 'WCR: replay paused') . 'WAIT'. 'ASM background timer') . 'EMON slave idle wait') . 'WAIT'. 'WAIT'. 'WAIT'. 'SQL*Net message from client') .gd(c.gd(c. 'auto-sqltune: wait graph update') . 'PL/SQL lock timer') . 'Streams fetch slave: waiting for tx ns') .gd(c.gd(c..gd(c. 'HS message to agent') . 'WCR: replay client notify') . 'WAIT'.gd(c. 'WAIT'.gd(c. 'WAIT'.gd(c. 'WAIT'.gd(c.gd(c. 'WAIT'. 'Streams AQ: waiting for messages in the queue') . 'SQL*Net vector message from client' ) . 'WAIT'.gd(c. 'Streams AQ: delete acknowledged mes sages') . 'WAIT'.gd(c. 'WAIT'. 'Streams AQ: deallocate messages fro m Streams Pool') . 'Streams AQ: qmn coordinator idle wa it') .gd(c.gd(c. 'WAIT'. 'WAIT'.gd(c.gd(c.gd(c. 'WAIT'.

abs(p _num)). end if. -.0) . end get_useful_average.p_grouplen)) ).mt=time.'TIME') then return round( p_num / power( p_base . end if. end case. mt). trunc(log(p_base. p_precision ) || case trunc(log(p_base.p_grouplen)) when 0 then 'us' when 1 then 'us' when p_grouplen*1 then 'ms' when p_grouplen*2 then 's' when p_grouplen*3 then 'ks' when p_grouplen*4 then 'Ms' else '*'||p_base||'^'||to_char( trunc(log(p_base. -. mn else null.p_grouplen)) )||' us' end.p_base=2 and p_groupl en=10 ) return varchar2 is begin if p_num = 0 then return '0'.function for converting large numbers to human-readable format ---------------------------------------------------*/ function tptformat( p_num in number. trunc(log(p_base. 10) || ' unaccounted time' ..p_grouplen)) when 0 then '' when 1 then '' when p_grouplen*1 then 'k' when p_grouplen*2 then 'M' when p_grouplen*3 then 'G' when p_grouplen*4 then 'T' .abs(p_num)))-trunc(mod(log(p_base.for KiB/MiB formattin g use p_grouplen in number default 3 -. p_precision in number default 2.abs(p_num)).abs(p_num)))-trunc( mod(log(p_base. if p_stype in ('WAIT'. if p_num IS NULL then return '~'.abs(p_num)).p_grouplen)) ).abs(p _num)).mt return ret.abs(p_num)). p_base in number default 10.abs(p_nu m)))-trunc(mod(log(p_base.abs(p_num)))-trunc(mod(log(p_base. p_precision ) || case trunc(log(p_base. else null. -. p_stype in varchar2 default 'STAT'. end case.abs(p_num)))-trunc( mod(log(p_base. else return round( p_num / power( p_base . /*---------------------------------------------------.

p_delim ) . -.simple function for parsing arguments from parameter string ---------------------------------------------------*/ function getopt( p_parvalues in varchar2.'\0')||']').' ) return varchar2 is ret varchar(1000) := NULL. end if. else ret := null. -.in case parameter was specified but with no valu e ). instr(p_parvalues.no parameter found end if. end.dbms_output.tptformat /*---------------------------------------------------.put('p_parvalues = ['||p_parvalues||'] ' ).put_line('ret = ['||replace(ret. . begin -. p_extract)+length (p_extract) ) .dbms_output. p_extract)+length(p_extract). instr(p_parvalues.1 end ) .chr(0).when p_grouplen*5 then 'P' when p_grouplen*6 then 'E' else '*'||p_base||'^'||to_char( trunc(log(p_base. p_delim in varchar2 default '.p_grouplen)) ) end. p_delim ) when 0 then length(p_parvalues) else instr( substr(p_parvalues. case instr( substr(p_parvalues.abs(p_num)).put('p_extract = ['||p_extract||'] ' ). p_extract)+length (p_extract) ) . p_extract in varchar2. instr(p_parvalues.dbms_output.abs(p_nu m)))-trunc(mod(log(p_base. if lower(p_parvalues) like lower(p_extract)||'%' or lower(p_parvalues) like '%'||p_delim||lower(p_extract)||'%' then ret := nvl ( substr(p_parvalues. chr(0) -. -. -.

l_return_sessions(tmp_sessions(i).'||tmp_sessions(i). end loop.sid) := tmp_ sessions(i). g_sessions := g_empty_sessions. end. machine etc -.'||tmp_sessions(i). osuser.. --(inst_id. -.inst_id||'.tmp_sessions.get_sessions /*---------------------------------------------------.sid). osuser. begin select /*+ unnest */ /* get_session_list:2 */ * bulk collect into tmp_sessions from gv$session s where 1=1 and (&sid_filter) .sid) in (&snapper_sid).sid) in (&snapper_sid).count loop g_sessions(tmp_sessions(i). begin select /*+ unnest */ /* get_session_list:1 */ * bulk collect into tmp_sessions from gv$session s where 1=1 and ( &sid_filter ) . l_return_sessions sestab. --(inst_id. for i in 1.return ret.getopt /*---------------------------------------------------. for i in 1.count loop --output('get_sessions i='||i||' sid='||tmp_sessions(i). end. . machine etc ---------------------------------------------------*/ procedure get_sessions is tmp_sessions tmp_sestab.this func does not update the g_sessions global array but returns session info as return value ---------------------------------------------------*/ function get_sessions return sestab is tmp_sessions tmp_sestab.inst_id||'. -. end loop..function for getting session list with username.tmp_sessions.sid) := tmp_sessions(i).proc for getting session list with username.

-.keep track how many times we sampled gv$session so we could calculate averages later on g_ash_samples_taken := g_ash_samples_taken + 1. -.first.return l_return_sessions. ash_i := g_sessions. if -. end.count). -.sitem_raw /*---------------------------------------------------. s gv$session%rowtype. while ash_i is not null loop s := g_sessions(ash_i).proc for resetting the snapper ash array ---------------------------------------------------*/ procedure reset_ash is begin g_ash_samples_taken := 0. end.sitem varchar2 function sitem(p in number) return varchar2 as begin return '<'||to_char(p)||'>'.count='||g_sessions.proc for getting ash style samples from gv$session ---------------------------------------------------*/ procedure extract_ash is ash_i varchar2(30).records to varchar2 ---------------------------------------------------*/ function sitem(p in varchar2) return varchar2 as begin return '<'||translate(p. end. 'YYYY-MM-DD HH24:MI:SS')||'>'.get_sessions /*---------------------------------------------------. '<>'.sitem number function sitem(p in date) return varchar2 as begin return '<'||to_char(p.reset_ash /*---------------------------------------------------. -. end.active.sitem date function sitem_raw(p in raw) return varchar2 as begin return '<'||upper(rawtohex(p))||'>'. end. '__')||'>'. begin -.clear g_ash g_ash := new sys.dbms_debug_vc2coll(). -. --output('g_sessions. on cpu .functions for extracting and converting gv$session -. -. end. -.

sql_child_number) &_NO_PLSQL_OBJ_ID ||sitem('N/A') &_NO_PLSQL_OBJ_ID ||sitem('N/A') &_NO_PLSQL_OBJ_ID ||sitem('N/A') &_NO_PLSQL_OBJ_ID ||sitem('N/A') &_YES_PLSQL_OBJ_ID ||sitem(s.sql_hash_value) ||sitem(s.8 -.count) := substr( sitem(s.plsql_entry_object_id) &_YES_PLSQL_OBJ_ID ||sitem(s.10g+ -. s. s.sql_hash_v alue||' sqlid='||s. g_ash.state != 'WAITING' and s.5 -. waiting for non-idle wait (s.sid != g_mysid) then --output('extract_ash: i='||i||' sid='||s.p3:=NULL.event) s ||sitem(s.4 -.inst_id) -.status = 'ACTIVE' and s.blocking_instance) ||sitem(s.wait_class) s.6 -.state = 'WAITING' and s.wait_class:='ON CPU'. end if.status = 'ACTIVE' and s.event:='ON CPU'.1 ||sitem(s.terminal) s ||sitem(s.30 byte -.64 byte -.p1:=NULL.machine) s ||sitem(s.p1) ||sitem(s.row_wait_block#) ||sitem(s. s.p3) ||sitem(s.3 -.(s.2 ||sitem(s.10g+ .row_wait_file#) ||sitem(s.sid != g_mysid ) or -.active.p2) ||sitem(s. -.username) -.7 -.state) ||sitem(s.sql_id). clear the past wait event details if s.30 byte s ||sitem(s.extend.sid) -.state:='ON CPU'. s. 10g+ ||sitem(s.if not actually waiting for anything.row_wait_obj#) ||sitem(s.p2:=NULL.row_wait_row#) ||sitem(s.state != 'WAITING' then s.max length 1000 bytes (due to dbms_debug_vc2coll) g_ash(g_ash.sid||' hv='||s.blocking_session_status) &_NO_BLK_INST ||sitem('N/A') &_YES_BLK_INST ||sitem(s.program) s ||sitem(s.plsql_entry_subprogram_id) &_YES_PLSQL_OBJ_ID ||sitem(s.sql_id) ||sitem(s.64 byte -.wait_class != ' Idle' and s.64 byte ----- 10g+ 10gR2+ 10gR2+ 10g+ -. --TODO: What do we need to do for 9i he re? s.plsql_object_id) ----------------------9 10 11 12 13 14 15 16 17 17 18 19 20 21 22 23 24 25 22 23 24 25 -. -.48 byte -.blocking_session) ||sitem(s.

plsql_subprogram_id) ||sitem(s. p_stats_string out sys. 10g+ . ss.inst_id.27 -.28 -. s.action) -. .statistic# .extract_ash /*---------------------------------------------------. -.service_name) s. '%'). '%'). '%').sid and (lv_gather like '%s%' or lv_gather like '%a%') and ss. lv_include_time 'tinclude=' )).statistic# in (select /*+ no_unn est */ statistic# from v$statname where lower(name) li ke '%'||lv_include_stat||'%' varchar2(1000) := nvl( lower(getopt('&snapper_options'.32 byte -. '%'). lv_include_wait 'winclude=' )).26 -. exception when no_data_found then output('error in extract_ash(): no_data_found for item '||i). end.sample is of an active session ash_i := g_sessions. varchar2(1000) := nvl( lower(getopt('&snapper_options'.client_identifier) s ||sitem(s.module) ||sitem(s.inst_id and s.64 byte s ||sitem(s.&_YES_PLSQL_OBJ_ID s ||sitem(s.inst_id = ss. varchar2(1000). s.* bulk collect into p_stats from ( select 'STAT' stype. 1. 1000). gv$sesstat ss where &sid_filter --(inst_id.sid) in (& snapper_sid) and s. -.sid.64 byte -. lstr begin p_snapdate := systimestamp.next(ash_i).29 -. end loop.value. end if. select /* get_session_stats */ p_snapdate ts. l_stats out ltab.48 byte -.proc for querying performance data into collections ---------------------------------------------------*/ procedure snap( p_snapdate out timestamp. p_stats out stab.dbms_debug_vc2coll) is lv_include_stat 'sinclude=' )).30 -. varchar2(1000) := nvl( lower(getopt('&snapper_options'. varchar2(1000) := nvl( lower(getopt('&snapper_options'. ss. null event_count from gv$session s. snapper_stats.sid = ss.pls_adjust statistic#. lv_include_latch 'linclude=' )).

seconds_in_wait. total_waits event_count from gv$session s. 'i') ) -union all select 'LATG'. s. gv$sess_time_model s t where &sid_filter --(inst_id.inst_id.sid and s.stat_id . lv_include_stat.event = en. en.inst_id and se.event# in (select event# from v$event_name where lower(name) li ke '%'||lv_include_wait||'%' or regexp_like (n ame. -1 sid. lv_include_wait. se. s.inst_id = se. v$event_name en where &sid_filter and s.inst_id. lv_include_time.pls_adjust statistic#.sid) in (&snapp er_sid) and (lv_gather like '%w%' or lv_gathe r like '%a%') and en.event||s.latch# + (select count(*) from v$statn ame) + (select count(*) from v$event _name) + 1 . nvl(se.inst_id.sid) in (& snapper_sid) and s.inst_id. s. st.pls_adjust statistic#. 'i') ) -union all select 'TIME' stype. st.sid. null event_count from gv$latch s .inst_id = st. s. s.inst_id and s.sid = se. s.gets + s.time_waited_micro. s.sid = st. s. null event_count from gv$session s.sid.or regexp_like (name . s.pls_adjust.0) + ( decode(se.sid and (lv_gather like '%t%' or lv_gathe r like '%a%') and st. 'i') ) -union all select 'WAIT'.immediate_gets value.event# + (select count(*) fro m v$statname) + 1 .event||'WAITING'. 0) * 1000000 ) value. gv$session_event se.stat_id in (select stat_id from gv$sys_time_model where lower(stat_nam e) like '%'||lv_include_time||'%' or regexp_like (s tat_name.name --and (se.value.state.

inst_id = sw.why1+s.indx &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER -.indx &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and why. 'instance')). 'instance')).indx + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from v$statn ame) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from v$event _name) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from gv$latc h) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 1 .why0+s.why1 + why.indx = dsc.why2 + sw.indx &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 and s. &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 s.pls_adjust statistic#. null event_count &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER from &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER x$kcbuwhy why.why2 value. to_number(sys_context('u serenv'. &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 s.indx = sw.indx + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER (select count(*) from v$statn ame) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER (select count(*) from v$event _name) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER (select count(*) from gv$latc h) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER 1 . . -1 sid.why0+why.deliberate cartesian join &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and (lv_gather like '%b%' or lv_gathe r like '%a%') regexp_like (name.inst_id &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and dsc. &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER why.why1+why.inst_id &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and why.why1+s. x$kcbwh w &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 where &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 s. to_number(sys_context('u serenv'.inst_id &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and why.inst_id = dsc.inst_id = sw. 'i') ) -&_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 union all &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 select 'BUFG'.why2+sw.indx &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and why.pls_adjust statistic#.other_wait > 0 &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER and dsc.why2 > 0 &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 and (lv_gather like '%b%' or lv_gathe r like '%a%') -&_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER union all &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER select 'BUFG'. &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER x$kcbsw sw &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER where &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER why.why0+s. &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER sw. &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER x$kcbwh dsc.why0 + why. -1 sid.oth er_wait value.indx = w.indx = sw.where &inst_filter and (lv_gather like '%l%' or lv_gather like '%a%') and latch# in (select latch# from v$lat chname where lower(name) like ' %'||lv_include_latch||'%' or lv_include_latch. null event_count &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 from x$kcbsw s.

'|| TO_CHAR(p_stats(s).2. null event_co .p_stats. '99 9999999999999999999999'))||'. '99 9999999999999999999999'))||'. 'YYYY-MM-DD HH24 :MI:SS.extend().dbms_debug_vc2coll().FF') ||'. lstr := p_stats(s).p_stats_string is a dbms_debug_vc2coll collection datatype for "p ersisting" stats values across snapper DB calls (for "before" and "after" snaps) p_stats_string := sys. event_count number ).ts.statistic#. sid number. s. statistic # number.eq_type.p_stats_string='||p_stats_string(s)).inst_id.'||trim(to_char(p_stats(s).p.sid))||'. if p_stats. -. (select count(*) from x$kcbwh 1 .'9 99999999999999999999999')).inst_id) ||'.'||trim(to_char(p_stats(s).last loop -.1))*256 + ascii(substr(s. end loop. used for the us eful averages calculation -. -.l_stats is an associative array for stats lookup.1.COUNT > 0 end snap. stype.eq_type.1)) + (select count(*) from v$statn ame) + (select count(*) from v$event _name) + (select count(*) from gv$latc h) + &_IF_X_ACCESSIBLE ) + unt from gv$enqueue_stat s where &inst_filter and (lv_gather like '%e%' or lv_gathe r like '%a%') ) snapper_stats order by inst_id.'|| TRIM(TO_CHAR(p_stats(s). s.sid) ||'.event_count.'|| TRIM(TO_CHAR(p_stats(s).'|| TO_CHAR(p_stats(s).'|| TRIM(TO_CHAR(p_stats(s). --output('p_stats. l_stats(lstr) := p_stats(s).stype ||'. p_stats_string(s) := TO_CHAR(p_stats(s). for s in p_stats.inst_id)) ||'.total_req# value.type srec is record (stype varchar2(4).stats. sid. end if.'||trim(to_char(p_stats(s).first.stype||'.'|| p_stats(s). statistic#.. -1 sid.COUNT > 0 then -. ascii(substr(s.-union all select 'ENQG'.s in (p_stats) end if. if g_snap_begin is not null then p_stats_string.value.'99 9999999999999999999999')). value number.statistic#.pls_adjust statistic#.

' ||trim(to_char(p_stats(s).'999999 999999999999999999')). p_topn in number := 10 ) as -.*?). lv_rec.proc for reversing the string-normalized -.'.statistic# := TO_NUMBER(replace(regexp_substr(p_string_sta ts(s)||'. '(.even t_count)).whether to print given column or not p_inst_id number := p_sid number := p_username number := p_machine number := p_terminal number := p_program number := p_event number := p_wait_class number := p_state number := p_p1 number := p_p2 number := p_p3 number := 0.'.stype||'. .'.*?). lv_rec.'. 0.*?).'. p_snapdate := lv_rec. 0.'')). p _snapdate out timestamp. lv_rec srec. lv_rec. 1.inst_id))||'.. 1).''). '(. p_string_stats.'.'. 0. lstr := p_stats(s).*?).inst_id := TO_NUMBER(replace(regexp_substr(p_string_sta ts(s)||'.sid))||'.FF'). 0.dbms_debug_vc2coll. event_count number ). 'YYYY-MM-DD HH24:MI:SS.value := TO_NUMBER(replace(regexp_substr(p_string_sta ts(s)||'.stype := replace(regexp_substr(p_string_sta ts(s)||'. --output('snap_from_stats_string.first . for s in p_string_stats. 3). 2).'||trim(to_char(p_stats(s). lv_rec.statistic#.'.stats array into lookup tables/collections ---------------------------------------------------*/ procedure snap_from_stats_string (p_string_stats in sys. lv_rec. 6).'. 1.event_count = '||to_char(lv_rec.'.sid := TO_NUMBER(replace(regexp_substr(p_string_sta ts(s)||'. 0.'. 0. p_stats out stab. sid number.'. '(. value number. l_stats(lstr) := p_stats(s). p_stats(s) := lv_rec. /*---------------------------------------------------. end snap_from_stats_string. 1.'.*?). 0. '(.'.event_count := TO_NUMBER(replace(regexp_substr(p_string_sta ts(s)||'.'. 7). 1. 0.ts := TO_TIMESTAMP(replace(regexp_substr(p_string_sta ts(s)||'. 0. 1.'.'.'||trim(to_char(p_stats(s).'. begin p_snapdate := NULL.'.'.'')). l_stats out ltab) is lstr varchar2(1000).last loop lv_rec.''). statistic# number.ts. '(.'. end loop.'')).proc for dumping ASH data out in grouped -.'./*---------------------------------------------------. 1.'')). 4). 0. lv_rec. 0. --type srec is record (stype varchar2(4). 1.*?).'')).'.'.'.*?).'. '(.'.'.and ordered fashion ---------------------------------------------------*/ procedure out_ash( p_ash_columns in varchar2. '(. 5).

varchar2(100).temporary variables for holding session details (for later formatting varchar2(100). varchar2(100). varchar2(100). varchar2(4000). number := 0. varchar2(100). varchar2(100). varchar2(100). varchar2(100). varchar2(100). varchar2(100). varchar2(100). 0. varchar2(100). 0. 0. 0. varchar2(100). 0. -. varchar2(100). varchar2(100). 0. 0. varchar2(100). 0. varchar2(100). varchar2(100). 0. varchar2(100). varchar2(100). 0.helper local vars l_ash_grouping l_output_line l_ash_header_line begin number number number number number number number number number number number number number number number number number number := := := := := := := := := := := := := := := := := := 0. varchar2(100). varchar2(100). varchar2(100). varchar2(100). varchar2(100).p_row_wait_obj# p_row_wait_file# p_row_wait_block# p_row_wait_row# p_blocking_session_status p_blocking_instance p_blocking_session p_sql_hash_value p_sql_id p_sql_child_number p_plsql_entry_object_id p_plsql_entry_subprogram_id p_plsql_object_id p_plsql_subprogram_id p_module p_action p_client_identifier p_service_name ) o_inst_id o_sid o_username o_machine o_terminal o_program o_event o_wait_class o_state o_p1 o_p2 o_p3 o_row_wait_obj# o_row_wait_file# o_row_wait_block# o_row_wait_row# o_blocking_session_status o_blocking_instance o_blocking_session o_sql_hash_value o_sql_id o_sql_child_number o_plsql_entry_object_id o_plsql_entry_subprogram_id o_plsql_object_id o_plsql_subprogram_id o_module o_action o_client_identifier o_service_name -. varchar2(100). 0. varchar2(100). 0. -. varchar2(100). 0. 0. varchar2(4000).bail out if no ASH samples recorded . 0. varchar2(100). varchar2(100). 0. 0.

1. then l_ash_grouping := l_ash_g . 1. 1. w_username . l_ash_header_line := l_ash_header_line || . ' '). ' '). 1. w_terminal . -. then l_ash_grouping := l_ash_g . l_ash_header_line := l_ash_header_line || . l_ash_header_line := l_ash_header_line || . w_program . '+' AS DELIMITER FROM DUAL ) CONNECT BY INSTR(TOKEN. w_state . w_p1 . 1. l_ash_header_line := 'Active%'. l_ash_header_line := l_ash_header_line || . then l_ash_grouping := l_ash_g . DELIMITER.ash3 parameter column group tokenizer for s in ( SELECT LEVEL . then l_ash_grouping := l_ash_g . then l_ash_grouping := l_ash_g . l_ash_header_line := l_ash_header_line || . INSTR(TOKEN. INSTR(TOKEN. then l_ash_grouping := l_ash_g .ash. then l_ash_grouping := l_ash_g . DELIMITER. DELIMITER. ' '). SUBSTR ( TOKEN .token -. l_ash_header_line := l_ash_header_line || . w_machine .actual column names when 'inst_id' c_inst_id lpad('INST_ID' when 'sid' c_sid lpad('SID' when 'username' c_username rpad('USERNAME' when 'machine' c_machine rpad('MACHINE' when 'terminal' c_terminal rpad('TERMINAL' when 'program' c_program rpad('PROGRAM' when 'event' c_event rpad('EVENT' when 'wait_class' c_wait_class rpad('WAIT_CLASS' when 'state' c_state rpad('STATE' when 'p1' c_p1 rpad('P1' in gv$session then l_ash_grouping := l_ash_g . LEVEL)>0 ORDER BY LEVEL ASC ) loop case s.count = 0 then output(' <No active sessions captured during the sampling period>') . then l_ash_grouping := l_ash_g . LEVEL) DECODE(LEVEL. ' '). l_ash_header_line := l_ash_header_line || . ' '). w_inst_id .ash1. 1. LEVEL-1)+1) .'')||'+' AS TOKEN . DECODE(LEVEL. l_ash_header_line := l_ash_header_line || . DELIMITER. l_ash_header_line := l_ash_header_line || . w_event . ' '). then l_ash_grouping := l_ash_g . ' '). 1. l_ash_header_line := l_ash_header_line || . INSTR(TOKEN.if g_ash. ' ').' '. 1. ' '). w_wait_class . return. LEVEL-1)+1) ) TOKEN FROM ( SELECT REPLACE( LOWER(p_ash_columns) . end if.ash2. w_sid . ' '). rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || rouping + ' | ' || .

l_ash_header_line := l_ash_header_line || ' | ' || rpad('SERVICE_NAME' . when 'service_name' then l_ash_grouping := l_ash_g rouping + c_service_name . when 'sql_child_number' then l_ash_grouping := l_ash_g rouping + c_sql_child_number . ' '). when 'p3' then l_ash_grouping := l_ash_g rouping + c_p3 . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_OBJECT_ID' . when 'sql_id' then l_ash_grouping := l_ash_g rouping + c_sql_id . l_ash_header_line := l_ash_header_line || ' | ' || rpad('CLIENT_IDENTIFIER' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_FILE#' . . when 'plsql_entry_object_id' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_object_id . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_BLOCK#' . when 'blocking_instance' then l_ash_grouping := l_ash_g rouping + c_blocking_instance . when 'sql_hash_value' then l_ash_grouping := l_ash_g rouping + c_sql_hash_value . ' '). w_plsql_entry_subprogram_id. when 'client_identifier' then l_ash_grouping := l_ash_g rouping + c_client_identifier . when 'row_wait_file#' then l_ash_grouping := l_ash_g rouping + c_row_wait_file# . w_client_identifier . when 'blocking_session_status' then l_ash_grouping := l_ash_g rouping + c_blocking_session_status . ' '). w_plsql_entry_object_id . ' '). ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_CHILD_NUMBER' . when 'row_wait_block#' then l_ash_grouping := l_ash_g rouping + c_row_wait_block# . w_row_wait_row# . ' '). w_blocking_session . w_module . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_OBJ#' . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_HASH_VALUE' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ACTION' . w_p2 . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_ROW#' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_OBJECT_ID' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_SUBPROGRAM_ID' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('P2' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('P3' . w_sql_id . w_action . ' '). ' '). w_blocking_session_status . w_sql_child_number . w_row_wait_block# . w_row_wait_obj# . ' '). when 'blocking_session' then l_ash_grouping := l_ash_g rouping + c_blocking_session . ' '). ' '). when 'row_wait_obj#' then l_ash_grouping := l_ash_g rouping + c_row_wait_obj# . l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION' . ' '). when 'plsql_entry_subprogram_id' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_subprogram_id. when 'module' then l_ash_grouping := l_ash_g rouping + c_module . when 'plsql_object_id' then l_ash_grouping := l_ash_g rouping + c_plsql_object_id . when 'action' then l_ash_grouping := l_ash_g rouping + c_action . l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_ID' . w_plsql_subprogram_id .when 'p2' then l_ash_grouping := l_ash_g rouping + c_p2 . ' '). w_service_name . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION_STATUS' . when 'plsql_subprogram_id' then l_ash_grouping := l_ash_g rouping + c_plsql_subprogram_id . when 'row_wait_row#' then l_ash_grouping := l_ash_g rouping + c_row_wait_row# . w_plsql_object_id . w_blocking_instance . w_sql_hash_value . w_p3 . l_ash_header_line := l_ash_header_line || ' | ' || rpad('MODULE' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_SUBPROGRAM_ID' . ' '). ' '). w_row_wait_file# . ' '). ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_INSTANCE' .

l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_INSTANCE' . w_service_name . ' '). when 'wait_event' then l_ash_grouping := l_ash_g . w_sql_hash_value . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_FILE#' . ' '). when 'sqlid' then l_ash_grouping := l_ash_g rouping + c_sql_id . ' '). w_row_wait_obj# . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_CHILD_NUMBER' .-. when 'plsql_oid' then l_ash_grouping := l_ash_g rouping + c_plsql_object_id . ' '). w_row_wait_block# . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION_STATUS' . ' '). when 'bsi' then l_ash_grouping := l_ash_g rouping + c_blocking_instance . when 'sql' then l_ash_grouping := l_ash_g rouping + c_sql_hash_value . l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_ID' . ' '). ' '). w_blocking_session_status . ' '). when 'child' then l_ash_grouping := l_ash_g rouping + c_sql_child_number .aliases for convenience (only either real name or alias should be used together at the same time) when 'user' then l_ash_grouping := l_ash_g rouping + c_username . when 'plsql_eoid' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_object_id . w_plsql_object_id . ' '). ' '). when 'plsql_esubpid' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_subprogram_id. when 'row' then l_ash_grouping := l_ash_g rouping + c_row_wait_row# . w_blocking_instance . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_OBJECT_ID' . w_plsql_entry_object_id . w_username . when 'mod' then l_ash_grouping := l_ash_g rouping + c_module . w_action . when 'block' then l_ash_grouping := l_ash_g rouping + c_row_wait_block# . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_OBJ#' . w_client_identifier . when 'plsql_subpid' then l_ash_grouping := l_ash_g rouping + c_plsql_subprogram_id . l_ash_header_line := l_ash_header_line || ' | ' || rpad('USERNAME' . when 'cid' then l_ash_grouping := l_ash_g rouping + c_client_identifier . w_plsql_subprogram_id . w_sql_id . when 'obj' then l_ash_grouping := l_ash_g rouping + c_row_wait_obj# . l_ash_header_line := l_ash_header_line || ' | ' || rpad('CLIENT_IDENTIFIER' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_SUBPROGRAM_ID' . ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_OBJECT_ID' . when 'act' then l_ash_grouping := l_ash_g rouping + c_action . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_BLOCK#' . ' '). w_blocking_session . l_ash_header_line := l_ash_header_line || ' | ' || rpad('MODULE' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('SERVICE_NAME' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('ACTION' . ' '). ' '). l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_ROW#' . l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_HASH_VALUE' . w_plsql_entry_subprogram_id. w_module . when 'service' then l_ash_grouping := l_ash_g rouping + c_service_name . l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_SUBPROGRAM_ID' . when 'file' then l_ash_grouping := l_ash_g rouping + c_row_wait_file# . w_row_wait_file# . ' '). w_row_wait_row# . w_sql_child_number . when 'bs' then l_ash_grouping := l_ash_g rouping + c_blocking_session . when 'bss' then l_ash_grouping := l_ash_g rouping + c_blocking_session_status . ' ').

'<'.rec.length(l_ash_header_line). '>')-1) terminal . '<'. substr(r. output(lpad('-'. '<'. when 'wait_state' then l_ash_grouping := l_ash_g rouping + c_state . -.rec. l_ash_header_line := l_ash_header_line || ' | ' || rpad('EVENT' . 1. 1)+1.rec. '<'. '>')-1) inst_id .rec. 1. 9)+1. 9)+1).rec.rec. 15)+1).rec.rec. 1.rec.rec.rec. ' '). 1.rec. '>')-1) p3 .raise_application_error(-20000.rec.rouping + c_event . instr (substr(r. 1. l_ash_header_line := l_ash_header_line || ' | ' || rpad('STATE' .rec. substr(r.rec. instr(r. instr(r. '<'.rec. 1. instr(r. '>')-1) event .rec. instr (substr(r. instr(r. instr (substr(r. '<'. '<'. 15)+1. '<'. instr(r.rec. instr(r. 1. '<'.'-')). '<'. instr(r. 7)+1).rec.rec. instr(r. -. instr(r.token end loop. '<'.rec. '<'.rec.rec.rec.'-')). '>')-1) p1 . substr(r. 1. 3)+1.rec. '>')-1) row_wait_block# . instr(r.rec. instr (substr(r. '<'.rec. 2)+1.rec. output(lpad('-'. '<'. instr(r. -.rec. instr(r.rec. instr(r. '<'.rec. 1. '>')-1) row_wait_obj# . 1)+1). '<'. instr(r. 1.rec. else null. 1.rec. 1. 1. 1. '>')-1) wait_class . instr(r. 1. '<'. instr (substr(r. 4)+1).rec.rec. instr(r. '<'. 4)+1. '<'.rec. '<'. '<'. 17)+1). '<'. instr (substr(r. substr(r.rec.rec. 1. substr(r. '>')-1) row_wait_file# . substr(r. 12)+1. instr(r. '<'. instr (substr(r.rec. 1.rec. 1. 1. instr (substr(r. instr(r. 1.rec. -. instr(r. instr(r. 1.rec. 1. '>')-1) row_wait_row# . instr (substr(r. '<'. 2)+1). instr(r. 8)+1). instr(r. instr(r. instr(r.rec.rec. '<'. '>')-1) p2 . ' ').tokenizer output(' '). '<'. '<'. 13)+1). 6)+1).rec. instr(r.rec.rec. 1. 7)+1.rec.rec. 1. substr(r. 5)+1). '<'. 16)+1).this is needed for "easy" sorting and group by ops (without any custom stored object types!) for i in ( with /* get_aggregates_from_ash */ raw_records as ( select column_value rec from table(cast(g_ash as sys.rec. instr(r. 11)+1).rec.rec. instr (substr(r. instr (substr(r. '>')-1) state . instr (substr(r. instr (substr(r. '>')-1) machine . '<'. substr(r. instr(r.rec. '>')-1) username . end case. 1. substr(r. 11)+1. instr(r. instr(r. 6)+1.rec. output(l_ash_header_line). '<'. substr(r. 14)+1. substr(r. w_event . 16)+1. instr (substr(r. 1. 1. '>')-1) program .rec. 12)+1). instr (substr(r.rec. w_state . 1. '>')-1) sid . 5)+1. 1.rec. instr (substr(r. substr(r. 1. '<'. 3)+1). 17)+1. instr (substr(r. 1.rec.rec. 1.rec.rec. 10)+1. instr(r. 1. substr(r.rec.rec.rec. 'Invalid ASH column name'). instr(r. instr(r. 13)+1. substr(r. substr(r. 14)+1). '<'. '>')-1) blocking_session_status .length(l_ash_header_line). ash_records as ( select substr(r.rec.case s.rec. substr(r.dbms_debug_vc2 coll)) ). '<'.rec. 10)+1). instr(r. instr(r. 8)+1.rec. 1. '<'.

1. 18)+1. '<'. 1.rec.rec. 27)+1). 1. '<'. chr(0). substr(r. 1. 24)+1. instr instr(r.rec. 29)+1). decode(bitand(l_ash_grouping. instr instr(r.rec. 25)+1. instr instr(r.rec. power(2. 1. '<'. '>')-1) sql_hash_value . power(2.rec.rec. '<'. 1. (substr(r. substr(r.. 0.rec. state ) as state . . '>')-1) plsql_entry_object_id . '<'. instr instr(r. instr(r. 0. event ) as event (substr(r.rec. (substr(r. power(2. substr(r. '<'.rec.rec. s_sid )). s_terminal )). instr instr(r. (substr(r. '<'. s_state )). 1. 1.rec. instr(r. wait_class ) as wait_class . '<'.rec. s_username )). '<'. decode(bitand(l_ash_grouping. '<'. 1. instr(r. s_program )). s_machine )). (substr(r. instr(r. 1. 0. (substr(r. 0. instr instr(r. '<'. substr(r. '>')-1) action . 21)+1). power(2. chr(0). (substr(r. 19)+1). 28)+1.rec. substr(r. '>')-1) blocking_session . substr(r. instr instr(r. '>')-1) module . 1. decode(bitand(l_ash_grouping. 1. 1. '<'. 22)+1.rec. instr instr(r. 0.rec.rec. 1. '<'. (substr(r. '<'. substr(r. 1. terminal ) as terminal .rec. '<'.rec. username ) as username . 23)+1). 23)+1.rec.rec. program ) as program . '<'. 1. power(2. '<'. 29)+1. power(2. 30)+1. 1. 1. instr(r. '<'. s_event )). '>')-1) client_identifier . instr instr(r. s_p1 )). decode(bitand(l_ash_grouping.rec. 19)+1. sid ) as sid . '<'. 0.rec. 1. decode(bitand(l_ash_grouping. 26)+1). '<'. substr(r. (substr(r. power(2. substr(r. chr(0).rec. 28)+1).rec. '<'. chr(0). s_wait_class )). chr(0). 22)+1). 1. 20)+1).rec.rec. instr(r. 27)+1.rec.rec. 1.rec. 1.rec. (substr(r. (substr(r. '>')-1) blocking_instance . 1.rec. instr(r. chr(0).rec. chr(0). '>')-1) sql_child_number .rec. instr(r. substr(r. 24)+1).rec. (substr(r.rec. 20)+1. power(2. 25)+1). 30)+1). '>')-1) plsql_subprogram_id .rec. decode(bitand(l_ash_grouping. instr instr(r. (substr(r. instr instr(r. '>')-1) plsql_object_id . 1. chr(0).rec. instr(r. substr(r. 0. machine ) as machine .rec.rec.rec. substr(r.rec. power(2. '<'.rec.rec. instr instr(r. instr(r. decode(bitand(l_ash_grouping. 1. '>')-1) service_name from raw_records r ) select * from ( select decode(bitand(l_ash_grouping. instr(r. power(2. s_inst_id )). '<'.rec. instr(r.rec. 26)+1. 0.rec. 0. '>')-1) plsql_entry_subprogram_id . 21)+1. 18)+1). '<'. decode(bitand(l_ash_grouping.rec. inst_id ) as inst_id . instr instr(r. chr(0).rec. '>')-1) sql_id . '<'.rec. chr(0).rec. 1.rec. '<'. decode(bitand(l_ash_grouping. p1 ) as p1 . instr(r. 0. substr(r.

decode(bitand(l_ash_grouping. decode(bitand(l_ash_grouping. s_module )). row_wait_row# ) as row_wait_row# . module ) as module . s_sql_hash_value )). blocking_instance ) as blocking_instance . s_plsql_entry_object_id )). 0. 0. power(2. s_blocking_session_status )). row_wait_file# ) as row_wait_file# . chr(0). s_row_wait_obj# )). chr(0). 0. chr(0). chr(0). chr(0). power(2. s_plsql_object_id )). blocking_session ) as blocking_session . power(2. plsql_object_id ) as plsql_object_id . decode(bitand(l_ash_grouping. 0. sql_id ) as sql_id . chr(0). decode(bitand(l_ash_grouping. 0. p3 ) as p3 . power(2. chr(0). decode(bitand(l_ash_grouping. plsql_subprogram_id ) as plsql_subprogram_id . s_blocking_instance )). service_name ) as service_name . decode(bitand(l_ash_grouping. chr(0). 0. power(2. chr(0). power(2. s_plsql_subprogram_id )). plsql_entry_subprogram_id ) as plsql_entry_subprogram_i . s_row_wait_file# )). plsql_entry_object_id ) as plsql_entry_object_id d d . power(2. power(2. decode(bitand(l_ash_grouping. power(2. power(2. row_wait_obj# ) as row_wait_obj# . power(2. s_p2 )). decode(bitand(l_ash_grouping. chr(0). s_service_name )). decode(bitand(l_ash_grouping. chr(0). 0. s_row_wait_block# )). s_plsql_entry_subprogram_i )). s_action )). 0. 0. decode(bitand(l_ash_grouping. power(2. decode(bitand(l_ash_grouping. p2 ) as p2 . 0. 0. blocking_session_status ) as blocking_session_status . 0. s_p3 )). 0. power(2. 0. 0. chr(0). decode(bitand(l_ash_grouping. s_blocking_session )). action ) as action . chr(0). chr(0). power(2. power(2. chr(0). power(2. power(2. decode(bitand(l_ash_grouping. s_client_identifier )). chr(0). 0. sql_child_number ) as sql_child_number . 0. power(2. decode(bitand(l_ash_grouping. sql_hash_value ) as sql_hash_value . chr(0). power(2. decode(bitand(l_ash_grouping. power(2. client_identifier ) as client_identifier . chr(0). decode(bitand(l_ash_grouping. 0. decode(bitand(l_ash_grouping. decode(bitand(l_ash_grouping. s_sql_id )). 0. chr(0). chr(0). row_wait_block# ) as row_wait_block# . s_row_wait_row# )). 0. decode(bitand(l_ash_grouping. s_sql_child_number )). decode(bitand(l_ash_grouping..

0. power(2. s_p1 )). 0. 0. p2 ) -.blocking_instance . chr(0). power(2. decode(bitand(l_ash_grouping. chr(0). s_terminal )). 0. decode(bitand(l_ash_grouping. row_wait_block# ) -. decode(bitand(l_ash_grouping. 0. event ) -.row_wait_file# . chr(0). s_event )).program . power(2.event .machine . chr(0). power(2. power(2. wait_class ) -. s_machine )). s_blocking_session )). power(2. decode(bitand(l_ash_grouping.row_wait_obj# . decode(bitand(l_ash_grouping. power(2. power(2. decode(bitand(l_ash_grouping. decode(bitand(l_ash_grouping. chr(0). 0. 0.state . 0. decode(bitand(l_ash_grouping. terminal ) -. p3 ) -. chr(0). 0. s_row_wait_row# )). power(2. chr(0). 0. s_state )). power(2. blocking_instance ) -. power(2. 0. username ) -. p1 ) -. inst_id ) -.sid .terminal . decode(bitand(l_ash_grouping. chr(0). decode(bitand(l_ash_grouping. row_wait_file# ) -. decode(bitand(l_ash_grouping. count(*)/g_ash_samples_taken average_active_samples from ash_records a group by decode(bitand(l_ash_grouping. s_blocking_session_status )). s_row_wait_obj# )). machine ) -. power(2. chr(0). chr(0).. power(2. decode(bitand(l_ash_grouping. sid ) -. chr(0). power(2. power(2. s_p3 )).blocking_session_status .inst_id . 0. power(2.p2 . decode(bitand(l_ash_grouping.row_wait_block# . decode(bitand(l_ash_grouping. 0. 0. row_wait_row# ) -.username . row_wait_obj# ) -. decode(bitand(l_ash_grouping. decode(bitand(l_ash_grouping. chr(0). s_blocking_instance )). chr(0). s_username )). chr(0). chr(0). decode(bitand(l_ash_grouping. decode(bitand(l_ash_grouping. chr(0).p1 . blocking_session ) -. s_program )). 0. 0. s_row_wait_file# )).blocking_session . chr(0). s_sid )). s_wait_class )).row_wait_row# .wait_class . state ) -. s_inst_id )).p3 . power(2. chr(0). power(2. s_row_wait_block# )). blocking_session_status ) -. power(2. 0. s_p2 )). 0. chr(0). program ) -. 0.

power(2. decode(bitand(l_ash_grouping.state . plsql_entry_object_id ) -. chr(0). . decode(bitand(l_ash_grouping. chr(0). plsql_object_id ) -. WHEN i. WHEN i. ' ') END.state WHEN i. power(2.program . service_name ) -. ' ') END.module . decode(bitand(l_ash_grouping. chr(0). client_identifier ) -.sql_child_number . chr(0). chr(0). s_sql_id )).sql_id . decode(bitand(l_ash_grouping.sql_hash_value .wait_class := CASE ELSE nvl(i.inst_id . WHEN i. chr(0). module ) -. s_plsql_subprogram_id )). power(2. s_action )). 0. s_module )). s_plsql_entry_object_id )). s_sql_hash_value )). o_inst_id = chr(0) THEN null o_sid = chr(0) THEN null o_username = chr(0) THEN null o_machine = chr(0) THEN null o_terminal = chr(0) THEN null o_program = chr(0) THEN null o_event = chr(0) THEN null o_wait_class = chr(0) THEN null o_state = chr(0) THEN null := CASE ELSE nvl(i. WHEN i. 0.action .plsql_object_id . 0.program := CASE ELSE nvl(i. ' ') END. 0. s_plsql_object_id )).client_identifier .plsql_subprogram_id . ' ') END.terminal .machine := CASE ELSE nvl(i. WHEN i. decode(bitand(l_ash_grouping. 0. 0.terminal := CASE ELSE nvl(i. power(2. 0. power(2.username . 0. sql_child_number ) -. decode(bitand(l_ash_grouping. chr(0). plsql_entry_subprogram_id ) -. ' ') END. power(2. 0. decode(bitand(l_ash_grouping.plsql_entry_subprogram_i . sql_id ) -. s_sql_child_number )). action ) -. 0..username := CASE ELSE nvl(i. power(2. power(2. ' ') END. decode(bitand(l_ash_grouping. ' ') END. s_service_name )).sid := CASE ELSE nvl(i. s_plsql_entry_subprogram_i )). ' ') END. power(2. power(2. WHEN i. chr(0). ' ') END. chr(0).plsql_entry_object_id d d . decode(bitand(l_ash_grouping. chr(0).wait_class . 0.inst_id := CASE ELSE nvl(i. WHEN i.service_name order by count(*)/g_ash_samples_taken desc ) where rownum <= p_topn ) loop l_output_line := ''. decode(bitand(l_ash_grouping. plsql_subprogram_id ) -.machine . s_client_identifier )). decode(bitand(l_ash_grouping.sid . power(2.event := CASE ELSE nvl(i. sql_hash_value ) -.event . WHEN i. chr(0).

p2 . SUBSTR ( TOKEN . ' ') END.row_wait_file# . ' ') END.action = chr(0) THEN null ELSE nvl(i. ' ') END. o_action := CASE WHEN i. o_blocking_session := CASE WHEN i.sql_hash_value = chr(0) THEN null ELSE nvl(i. o_p3 := CASE WHEN i. DELIMITER.row_wait_obj# . o_plsql_object_id := CASE WHEN i. ' ') END. ' ') END.p3 .row_wait_block# = chr(0) THEN null ELSE nvl(i. 1.row_wait_file# = chr(0) THEN null ELSE nvl(i.sql_child_number . o_p2 := CASE WHEN i.row_wait_row# = chr(0) THEN null ELSE nvl(i.blocking_instance .service_name = chr(0) THEN null ELSE nvl(i.print the activity % as the first column l_output_line := lpad(to_char(round(i. o_client_identifier := CASE WHEN i.sql_id = chr(0) THEN null ELSE nvl(i.o_p1 := CASE WHEN i. ' ') END. 1.plsql_entry_object_id = chr(0) THEN null ELSE nvl(i.module = chr(0) THEN null ELSE nvl(i.plsql_entry_object_id .blocking_instance = chr(0) THEN null ELSE nvl(i.sql_id . ' ') END. DECODE(LEVEL.sql_child_number = chr(0) THEN null ELSE nvl(i. 1. o_blocking_instance := CASE WHEN i.blocking_session_status .plsql_object_id = chr(0) THEN null ELSE nvl(i. LEVEL-1)+1 ) ) TOKEN FROM ( SELECT REPLACE( LOWER(p_ash_columns) .blocking_session_status = chr(0) THEN null ELSE nvl(i. ' ') END. ' ') END. 1. o_sql_child_number := CASE WHEN i. ' ').plsql_subprogram_id = chr(0) THEN null ELSE nvl(i. 1. ' ') END.row_wait_obj# = chr(0) THEN null ELSE nvl(i. ' ') END.plsql_object_id . o_row_wait_file# := CASE WHEN i. o_blocking_session_status := CASE WHEN i.loop through ash columns to find what to print and in which order for s in ( SELECT LEVEL .p2 = chr(0) THEN null ELSE nvl(i.'')||'+' AS TOK . DELIMITER. o_sql_id := CASE WHEN i.blocking_session = chr(0) THEN null ELSE nvl(i.row_wait_row# .sql_hash_value .blocking_session . LEVEL-1 )+1) . o_row_wait_block# := CASE WHEN i. o_plsql_entry_object_id := CASE WHEN i. 1.plsql_subprogram_id . ' ') END.service_name . o_sql_hash_value := CASE WHEN i. o_plsql_entry_subprogram_id := CASE WHEN i. -.average_active_samples*100))||'% '. ' ') END. w_activity_pct. ' ') END.plsql_entry_subprogram_id = chr(0) THEN null ELSE nvl(i. INSTR(TOKEN. DELIMITER. ' ') END. ' ') END. o_row_wait_obj# := CASE WHEN i. ' ') END. 1. o_service_name := CASE WHEN i. o_plsql_subprogram_id := CASE WHEN i.p1 = chr(0) THEN null ELSE nvl(i.client_identifier = chr(0) THEN null ELSE nvl(i. INSTR(TOKEN.p3 = chr(0) THEN null ELSE nvl(i.row_wait_block# . ' ') END. -. ' ') END. o_row_wait_row# := CASE WHEN i.client_identifier . o_module := CASE WHEN i.p1 .action . LEVEL) DECODE(LEVEL.plsql_entry_subprogram_id . ' ') END.' '. ' ') END. INSTR(TOKEN.module .

' ') when 'blocking_instance' then nstance . ' ') when 'event' then . w_terminal . w_username . ' ') when 'sql_child_number' then number . ' ') lpad(o_inst_id lpad(o_sid rpad(o_username rpad(o_machine rpad(o_terminal rpad(o_program rpad(o_event rpad(o_wait_class rpad(o_state rpad(o_p1 rpad(o_p2 rpad(o_p3 rpad(o_row_wait_o rpad(o_row_wait_f rpad(o_row_wait_b rpad(o_row_wait_r rpad(o_blocking_s rpad(o_blocking_i rpad(o_blocking_s rpad(o_sql_hash_v rpad(o_sql_id rpad(o_sql_child_ rpad(o_plsql_entr rpad(o_plsql_entr . ' ') when 'sid' then . '+' FROM DUAL AS DELIMITER ) CONNECT BY INSTR(TOKEN. w_plsql_entry_object_id . ' ') when 'sql_id' then . w_blocking_instance . w_row_wait_file# . ' ') when 'row_wait_block#' then lock# . w_blocking_session_status . ' ') when 'program' then . ' ') when 'row_wait_obj#' then bj# .actual column names in gv$session when 'inst_id' then . w_row_wait_row# . ' ') when 'state' then . w_state . w_event . w_wait_class . w_row_wait_obj# . ' ') when 'row_wait_row#' then ow# . ' ') when 'blocking_session' then ession . w_sql_hash_value . ' ') when 'plsql_entry_subprogram_id' then y_subprogram_id . w_machine .token -. ' ') when 'wait_class' then . ' ') when 'p2' then . ' ') when 'row_wait_file#' then ile# . ' ') when 'terminal' then . w_blocking_session . w_plsql_entry_subprogram_id. ' ') when 'sql_hash_value' then alue . LEVEL)>0 ORDER BY LEVEL ASC ) loop l_output_line := l_output_line || ' | ' || case s. w_inst_id . ' ') when 'blocking_session_status' then ession_status . 1. w_sql_id . ' ') when 'p1' then . ' ') when 'plsql_entry_object_id' then y_object_id . w_p3 . w_sid . w_program . ' ') when 'machine' then . w_sql_child_number . w_p2 . ' ') when 'username' then . w_p1 . w_row_wait_block# . ' ') when 'p3' then . DELIMITER.EN .

' when 'mod' . ' when 'block' lock# . w_blocking_instance . ' when 'plsql_esubpid' y_subprogram_id . w_plsql_entry_object_id .when 'plsql_object_id' . ' when 'row' ow# . ' when 'plsql_subprogram_id' rogram_id . w_plsql_subprogram_id . ' else '' end. w_row_wait_file# . w_username . ' when 'service_name' me . w_client_identifier .case s. ' when 'plsql_oid' ct_id . w_row_wait_obj# . ' when 'module' .token ct_id then rpad(o_plsql_obje ') then rpad(o_plsql_subp ') then rpad(o_module ') then rpad(o_action ') then rpad(o_client_ide ') then rpad(o_service_na ') (only either real name or alias then rpad(o_username ') then rpad(o_row_wait_o ') then rpad(o_row_wait_f ') then rpad(o_row_wait_b ') then rpad(o_row_wait_r ') then rpad(o_blocking_s ') then rpad(o_blocking_i ') then rpad(o_blocking_s ') then rpad(o_sql_hash_v ') then rpad(o_sql_id ') then rpad(o_sql_child_ ') then rpad(o_plsql_entr ') then rpad(o_plsql_entr ') then rpad(o_plsql_obje ') then rpad(o_plsql_subp ') then rpad(o_module ') then rpad(o_action ') then rpad(o_client_ide ') then rpad(o_service_na ') then rpad(o_event ') then rpad(o_state ') . ' when 'bsi' nstance . w_module . w_action . w_event . ' when 'action' . w_service_name . w_blocking_session_status . w_plsql_entry_subprogram_id. ' when 'act' . ' when 'service' me . w_blocking_session . ' when 'cid' ntifier . w_plsql_subprogram_id . w_module . w_row_wait_block# . w_action . ' when 'sqlid' . ' when 'obj' bj# . ' when 'wait_state' . ' when 'wait_event' . ' -. ' when 'file' ile# . ' when 'bss' ession_status . w_row_wait_row# . w_service_name . ' when 'client_identifier' ntifier . w_sql_child_number . ' when 'plsql_subpid' rogram_id . ' when 'bs' ession . w_sql_id . ' when 'plsql_eoid' y_object_id . ' when 'child' number . w_state . ' when 'sql' alue . w_plsql_object_id . w_plsql_object_id . w_sql_hash_value .aliases for convenience should be used together at the same time) when 'user' . w_client_identifier . -.

gather_stats := 1. g_snap_begin := lower(getopt('&snapper_options'. 'st w') end. 'pagesize=' ). --lv_gather:=getopt ('&snapper_options'. if pagesize > 0 then output(' '). gather_ash := 1. 'ash').tan elpoder.com ) . 'all') is not null then --output('setting stats to all due to option = all'). --output ( 'Pagesize='||pagesize ).Session Snapper v4.09 BETA . output('-. 'all') = chr(0) then ' chr(0)' when getopt('&snapper_options'. else if (lv_ash is null and lv_stats is null) then gather_stats := 0.Enjoy the Most Advanced Oracle Troubleshooting Script on the Pla net! :)'). 'all') is null then 'null' else (getopt( '&snapper_options'. lv_stats := getopt('&snapper_options'. if lv_stats is not null then gather_stats := 1.some additional default value logic if getopt('&snapper_options'. -. pagesize := nvl( getopt('&snapper_options'.and it begins!!! begin -. . 'gather=')). g_snap_end := lower(getopt('&snapper_options'. if lv_ash is not null then gather_ash := 1. 'end' )).'all')) end). 'gather='). pagesize). end loop. output(' '). end if. --output('g_snap_begin = '||g_snap_begin). --output('all='||case when getopt('&snapper_options'. 'gather=')). --output('lv_gather='||lv_gather). end if. 'stat'). 'begin' )).by Tanel Poder ( http://blog.ash parameter tokenizer output(l_output_line).grouped ash samples end out_ash. -.determine which performance counters and stats to collect lv_gather := case nvl( lower(getopt ('&snapper_options'. --output('g_snap_end = '||g_snap_end).get snappers own sid into g_mysid select sid into g_mysid from v$mystat where rownum = 1. end if. -.end loop. -. lv_ash := getopt('&snapper_options'. 'stw') when 'all' then 'stw' else nvl( lower(getopt ('&snapper_options'. end if. gather_ash := 1. -.

event# + (select count(*) from v$statnam e) + 1 .pls_adjust statistic#.pls_adjust stati stic#.eq_type. statistic# . stat_name name from gv$sys_time_model where (lv_gather like '%t%' or lv_gather like ' %a%') -union all select 'LATG'.1.fetch statistic names with their adjusted IDs select /* get_stat_names */ * bulk collect into sn_tmp from ( select 'STAT' stype. -.pls_adjust statistic#. &_IF_X_ACCESSIBLE kcbwhdes name &_IF_X_ACCESSIBLE from x$kcbwh &_IF_X_ACCESSIBLE where (lv_gather like '%b%' or lv_gather like '%a%') -union all select 'ENQG'. stat_id . &_IF_X_ACCESSIBLE indx + &_IF_X_ACCESSIBLE (select count(*) from v$statname) + &_IF_X_ACCESSIBLE (select count(*) from v$event_name) + &_IF_X_ACCESSIBLE (select count(*) from gv$latch) + &_IF_X_ACCESSIBLE 1 .pls_adjust statistic#.1))*256 + ascii( substr(e. . name from v$event_name where (lv_gather like '%w%' or lv_gather like ' %a%') -union all select 'TIME' stype.pls_adjust st atistic#.2.eq_type.initialize statistic and event name array -.latch# + (select count(*) from v$statname) + (select count(*) from v$event_name) + 1 .1)) + (select count(*) from v$statname) + (select count(*) from v$event_name) + (select count(*) from gv$latch) + &_IF_X_ACCESSIBLE (select count(*) from x$kcbwh) + 1 .pls_adjust. name from v$statname where (lv_gather like '%s%' or lv_gather like ' %a%') -union all select 'WAIT'. ascii(substr(e. l. name from gv$latch l where (lv_gather like '%l%' or lv_gather like ' %a%') -&_IF_X_ACCESSIBLE union all &_IF_X_ACCESSIBLE select 'BUFG'.end if.

sn_reverse(sn_tmp(i).statistic#) := sn_tmp(i).count loop sn(sn_tmp(i).name) := sn_tmp(i).' ')||'. end loop.' = 1 THEN ' %TIME.' = 1 THEN ' TYPE.'||lt.' = 1 THEN ' SNAPSHOT START = 1 THEN ' SECONDS. gv$lock_type lt where es. -. -.type ) e where (lv_gather like '%e%' or lv_gather like ' %a%') ) snapper_statnames order by stype.' = 1 THEN ' HDELTA/SEC.eq_type ||' .' = 1 THEN ' HDELTA. = 1 THEN ' DELTA/SEC.store these into an index_by array organized by statistic# for fast looku p for i in 1.' = 1 THEN ' SID @INST.print header if required gv_header_string := CASE WHEN output_header END || CASE WHEN output_inst END || CASE WHEN output_sid END || CASE WHEN output_inst_sid END || CASE WHEN output_username END || CASE WHEN output_time ' END || CASE WHEN output_seconds END || CASE WHEN output_stype END || CASE WHEN output_sname .' = 1 THEN ' INST.' = 1 THEN ' USERNAME .. total_req# from gv$enqueue_stat es .stype||'.name eq_type. statistic#.sesstat and other performance counter sampling if gather_stats = 1 then -.main sampling loop for c in 1.sn_tmp.' END || CASE WHEN output_delta END || CASE WHEN output_delta_s END || CASE WHEN output_hdelta END || CASE WHEN output_hdelta_s END || CASE WHEN output_percent END = 1 THEN 'HEAD.'||sn_tmp(i).&snapper_count loop -.' = 1 THEN rpad(' STATISTIC'.eq_type = lt.eq_type from ( select es.' .59 = 1 THEN ' DELTA..' = 1 THEN ' SID.' .

-. end if. if g_snap_end is not null then &_MANUAL_SNAPSHOT fetch :snapper bulk collect into g_snap1.manual before/after snapshots (snapper v4) if g_snap_begin is not null or g_snap_end is not null then if g_snap_begin is not null then get_sessions. s1. snap(d1. = 1 THEN ' GRAPH = 1 THEN ' NUM_WAITS. &_MANUAL_SNAPSHOT open :snapper for select column_value rec from table(g_snap1 ).s1.|| CASE WHEN output_pcthist END || CASE WHEN output_eventcnt END END || CASE WHEN output_eventavg ' END .. end if. l_stats out ltab) snap_from_stats_string(g_snap1. p_stats out stab. p_snapdate out date. else if pagesize = -1 and c = 1 then output(gv_header_string).s1.l1.' || CASE WHEN output_eventcnt_s = 1 THEN ' WAITS/SEC. end if.' = 1 THEN ' AVERAGES if g_snap_begin is null then if pagesize > 0 and mod(c-1. d1.l1. output(rpad('-'.'-')). else output('Taking BEGIN sample . s1 := s2.' .TODO raise an error if both begin and end are used together -.length(gv_header_string). else get_sessions.You should run snapper with BEGIN option first! -.g_snap1). output(gv_header_string). g_snap1 := g_snap2. pagesize) = 0 then output(rpad('-'.if you see this error then run: "VAR SNAPPER REFCURSOR" first! exit. end if.TODO conditionally comment out the refcursor use unless begin and end is used -. d1 := d2. -. l1).d bms_debug_vc2coll.procedure snap_from_stats_string (p_string_stats in sys. end if. end if. -. -. snap(d1.').length(gv_header_string)..gather_stats = 1 .'-')). else -. -.normal interval sampling if c = 1 then get_sessions.g_snap1). end if.c = 1 end if.

end if.at 1Hz &_USE_DBMS_LOCK dbms_lock. pagesize) = 0 then -. i :=1.1. while ( a <= s1. missing_values_s2 := 0.g_snap2).count > 0 then lv_curr_sid := s2(b).if filtering specific stats.sid then if pagesize > 0 and mod(c-1. &_USE_DBMS_LOCK extract_ash(). missing_values_s1 := 0. assuming that it's bette r to not leave spaces between every session data if getopt('&snapper_options'.(least(1. 'tinclude=' )||getopt('&snapper_options'.sid. -.iteration counter (for debugging) a :=1. &_USE_DBMS_LOCK if gather_ash = 1 then &_USE_DBMS_LOCK while sysdate < (ash_date1 + (&snapper_sleep/86400)) loop &_USE_DBMS_LOCK -.sleep( greatest(0.why not use a SQL join? this would require creation of PL/SQL -. but Snapper does not require any changes -.collection object types. -. &_USE_DBMS_LOCK -. -. &_USE_DBMS_LOCK end if.l2. 'winclude=' ) is null t hen .sysda te)*86400 ). snap(d2.sleep( ((ash_date1+(&snapper_sleep/86400)) .for longer duration sampling the algorithm will back off and for long durations (over 100 sec) the sampling rate will stabilize &_USE_DBMS_LOCK -.count and b <= s2. 'sinclude=')||getopt('&sna pper_options'.sesstat new sample and delta calculation if gather_stats = 1 then get_sessions.s2.message for each statistic row of that disappeared sid disappeared_sid := 0.manually coded nested loop outer join for calculating deltas: -.-.ASH style sampling &_USE_DBMS_LOCK ash_date1 := sysdate. so any custom object types are out! changed_values := 0. &_USE_DBMS_LOCK else &_USE_DBMS_LOCK dbms_lock. &_USE_DBMS_LOCK ash_date2 := sysdate. -.sleep timeout backoff depending on the duration sampl ed (for up to 10 seconds total sampling time will get max 100 Hz sampling) &_USE_DBMS_LOCK -.&snapper_sleep*&s napper_count/100))) ). &_USE_DBMS_LOCK end loop. -. &_USE_DBMS_LOCK null.s1 array index b :=1.s2 array index if s2.to the database.remember last disappeared SID so we wouldn't need to output a war ning -.get active session records from g_sessions &_USE_DBMS_LOCK get_sessions.count ) loop if lv_curr_sid != 0 and lv_curr_sid != s2(b). -.

s1(a). end if.'-')).event_count.value.statistic# < s2(b). a='||to_char(a)||' b='||to_char(b)||' s1.sid. if delta != 0 then fout().output(rpad('-'. b := b + 1.statistic# s2(b). --output('DEBUG. when s1(a).count='||s2. delta := 0.sid then case when s1(a). b := b + 1. a := a + 1.count||' s2.s1(a).output(' ').output(rpad('-'.count='||s2 .s1(a).count='||s2 .event_count. end if. a='||to_char(a)||' b='||to_char(b)||' s1. evcnt := s2(b).count||' s2.count='||s1.statistic# then delta := s2(b)..statist ic#. a='||to_char(a)||' b='||to_char(b)||' s1.count='||s2. s1(a). evcnt := s2(b).event_count. when s1(a). a := a + 1. end if.count='||s 2.don't print case when s1(a). if delta != 0 then fout(). -.count||' s2.count='||s2. b := b + 1.count||' s2. end case. lv_curr_sid := s2(b). b := b + 1. a := a + 1.statisti c#.statistic# .value . b := b + 1.value. -.statisti c#.statistic# = s2(b).event_count . if delta != 0 then fout(). -.statistic# < s2(b).count='||s1.length(gv_header_string). -.output(gv_header_string).statistic# then delta := s2(b).length(gv_header_string).count||' s2.value.statistic# when s1(a).statistic# > s2(b).sid = s2(b). s2(b). .count).count). end if. evcnt := s2(b). else output('ERROR.statistic# then output('ERROR.count).count='||s1.sid then delta := s2(b).'-')). s1(a). s1(a). end if.sid > s2(b)..statistic# ? s2(b). -.count||' s2. end if.

when s1(a).s1(a). end if. seconds='||round(get_seconds(d2-d1). 'ash2' ) = chr(0) then g_ash_colum getopt('&snapper_options'.while ( a <= s1.count='||s1.coun t||')'). Should not be here. g_ash_c olumns )..count ) if pagesize > 0 and changed_values > 0 then output(' '). g_ash_columns3 := case when getopt('&snapper_options'. 'ash2=' ) end.sid.count). 'ash3' ) is n null when getopt('&snapper_options'. seconds='||to_char(case get_seconds(d2-d1) whe n 0 then (&snapper_sleep) else round(get_seconds(d2-d1).get ASH sample grouping details g_ash_columns := nvl( getopt('&snapper_options'. end if. output('-. end='||to_char (d2. 1) end)). ignoring SID='||to_char(s1(a).count='||s1.sid then output('WARN.. end if. -.count||' s2. 'ash=' ). else output('ERROR.sid then if disappeared_sid != s1(a). 'YYYY-MM-DD HH24:MI:SS')||'.count||' s2. disappeared_sid := s1(a). 10 ).count||' s2.sid < s2(b). a := a + 1. ull then ns1 else ull then ns2 else ull then ns3 else .End of Stats snap '||to_char(c)||'. g_ash_columns2 := case when getopt('&snapper_options'. 'ash1' ) = chr(0) then g_ash_colum getopt('&snapper_options'. 'ash3' ) = chr(0) then g_ash_colum getopt('&snapper_options'.sid i:=i+1.count='||s2. end case. -.optional additional ASH groupings g_ash_columns1 := case when getopt('&snapper_options'.count='||s2. end if. 'ash1' ) is n null when getopt('&snapper_options'.sid .count and b <= s2. -. s2(b). Session has disappeared since previous snapshot. SID='||to_char(s2(b).count='||s2. output(' '). -. 'YYYY-MM-DD HH24:MI:SS')||'. 'ash1=' ) end. if delta != 0 then changed_values := changed_values + 1.group ASH records and print report out_ash( g_ash_columns. 1)).sid)||' debug(a='||to_char(a)||' b='||t o_char(b)||' s1. --output('-.count||' s2. -.End of Stats snap '||to_char(c)||'. 'ash3=' ) end. sid)||' a='||to_char(a)||' b='||to_char(b)||' s1.delta != 0 end loop. -. end='||to_char(d 2. 'ash2' ) is n null when getopt('&snapper_options'.count=' ||s2.gather_stats = 1 if gather_ash = 1 then -.

end if.group and print optional ASH reports if g_ash_columns1 is not null then out_ash( g_ash_columns1. if g_ash_columns3 is not null then out_ash( g_ash_columns3. if g_ash_columns2 is not null then out_ash( g_ash_columns2. en d if. / undefine snapper_oraversion undefine snapper_sleep undefine snapper_count undefine snapper_sid undefine ssid_begin undefine _IF_ORA11_OR_HIGHER undefine _IF_LOWER_THAN_ORA11 undefine _NO_BLK_INST undefine _YES_BLK_INST undefine _NO_PLSQL_OBJ_ID undefine _YES_PLSQL_OBJ_ID undefine _IF_DBMS_SYSTEM_ACCESSIBLE undefine _IF_X_ACCESSIBLE undefine _MANUAL_SNAPSHOT undefine _USE_DBMS_LOCK col snapper_ora11higher clear col snapper_ora11lower clear col dbms_system_accessible clear col x_accessible clear col no_plsql_obj_id clear col yes_plsql_obj_id clear col no_blk_inst clear col yes_blk_inst clear col manual_snapshot clear col use_dbms_lock clear col snapper_sid clear col sid_filter clear col inst_filter clear set serveroutput off .End of ASH snap '||to_char(c)||'.End of ASH snap '||to_char(c)||'. seconds='||to_char(round((ash_date2-ash_dat e1) * 86400. end='||to_char(ash _date2. -. if pagesize > 0 then output(' ').. 'YYYY-MM-DD HH24:MI:SS')||'. samples_taken='||g_ash_samples_taken). 10 ). reset_ash().-.for c in 1. output(' '). --output('-. seconds='||to_char(case (ash_date2-ash_da te1) when 0 then (&snapper_sleep) else round((ash_date2-ash_date1) * 86400. samples_taken='||g_ash_samples_taken). 10 ).gather_ash = 1 end loop. en d if. 'YYYY-MM-DD HH24:MI:SS')||'. 10 ). en d if. output('-. 1))||'. 1) e nd)||'.snapper_count end. -. end='||to_char(a sh_date2. end if.