Sunteți pe pagina 1din 49

---------------------------------------------------------------------------------- File name: snapper.

sql -- 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 works on Oracle 10.1 onwards. If you need Snapper for -s --nts ---- Note1: ----- Note2: t ------ Author: -- Copyright: ed. --- Disclaimer: are -ur ---- License: s for free older database versions, then Snapper v3 works on Oracle version starting from Oracle 9.2, but it does not have GV$ view, manual snapshot support and the useful averages are limited to wait eve only The "ASH" functionality in Snapper just samples V$SESSION view, so you do NOT need Diagnostics Pack licenses to use Snapper's "ASH" output Snapper just reports you performance metric deltas in a snapspho and does not attempt to solve any performance problems for you. You still need to interpret and understand these standard Oracle metrics yourself Tanel Poder (tanel@tanelpoder.com) (c) Tanel Poder - http://blog.tanelpoder.com - All rights reserv This script is provided "as is", so no warranties or guarantees made about its correctness, reliability and safety. Use it at yo own risk! 1) You may use this script for your (or your businesses) purpose

-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 and Marcus Mnnig for bugfixes, -additions and improvements ----------------------------------------------------------------------------------- The Session Snapper v3.63 -- (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 v$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 v$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 v$sesstat,v$sess_time_model,v$session_event perfor mance 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 v$sesstat -t - Session Time model info from v$sess_time_model -w - Session Wait statistics from v$session_event and v$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 V$SESSTAT stats which match the -LIKE pattern of sinclude (REGEXP_LIKE in 10g+) -linclude - if specified, then show only V$LATCH latch stats which ma tch the -LIKE pattern of linclude (REGEXP_LIKE in 10g+) -tinclude - if specified, then show only V$SESS_TIME_MODEL stats whic h match the -LIKE pattern of tinclude (REGEXP_LIKE in 10g+) -winclude - if specified, then show only V$SESSION_EVENT wait stats w hich 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 v$session" as value for <sid s_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 you can write such expressions for snapper's <sids_to_sna p> parameter: --sid=123 -- take sid 123 only (the same as just writing 123) -user=tanel -- take all sessions where username is 'tanel' (case inse nsitive) --- this is the same as writing following subquery for the --- <sids_to_snap> parameter: -select sid from v$session where lower(username) li ke 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 v$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, v$sesstat and v$sess_time_model statistics are reported by defaul t -Starting from V3 the ASH style session activity report is shown as well ) --@snapper stats,gather=w 1 1 515 -(Output one 1-second snapshot of session 515 using dbms_output and exit -only Wait event statistics are reported, no ASH) --@snapper ash,gather=st 1 1 515 -(Output one 1-second snapshot of session 515 using dbms_output and exit -only v$sesstat and v$sess_Time_model statistics are gathered + ASH) --@snapper trace,ash,gather=stw,pagesize=0 10 90 117,210,313 -(Write 90 10-second snapshots into tracefile for session IDs 117,210,313 -all statistics are reported, do not print any headers) --@snapper trace,ash 900 999999999 "select sid from v$session" -(Take a snapshot of ALL sessions every 15 minutes and write the output t o trace, -loop (almost) forever ) --@snapper out,trace 300 12 "select sid from v$session where username='APP S'" -(Take 12 5-minute snapshots of all sessions belonging to APPS user, writ e -output to both dbms_output and tracefile) --- Notes: --Snapper does not currently detect if a session with given SID has -ended and been recreated between snapshots, thus it may report bogus -statistics for such sessions. The check and warning for that will be -implemented in a future version. --------------------------------------------------------------------------------set termout off tab off verify off linesize 999 trimspool on trimout on null "" -- Get parameters define snapper_options="&1" define snapper_sleep="&2" define snapper_count="&3" define snapper_sid="&4" -- The following code is required for making this script "dynamic" as due to -- different Oracle versions, script parameters or granted privileges some -- statements might not compile if not adjusted properly. define _IF_ORA9="" define _IF_ORA9206_OR_LOWER="" define _IF_ORA9207_OR_HIGHER="" define _IF_ORA10_OR_HIGHER="" define _IF_ORA10_OR_HIGHER="--" define _IF_ORA11_OR_HIGHER="--" define _IF_LOWER_THAN_ORA11="--" define _IF_DBMS_SYSTEM_ACCESSIBLE="/* dbms_system is not accessible" /*dummy*/ -- it's here to avoid vim syntax highlighter from going crazy define _IF_X_ACCESSIBLE="--"

-- plsql_object_id columns available in v$session (from 10.2.0.3) define _YES_PLSQL_OBJ_ID="--" define _NO_PLSQL_OBJ_ID="" -- blocking_instance available in v$session (from 10.2) define _YES_BLK_INST="--" define _NO_BLK_INST="" -- 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_ora9 &noprint new_value _IF_ORA9 col snapper_ora9206lower &noprint new_value _IF_ORA9206_OR_LOWER col snapper_ora9207higher &noprint new_value _IF_ORA9207_OR_HIGHER col snapper_ora10higher &noprint new_value _IF_ORA10_OR_HIGHER 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 snapper_sid &noprint new_value snapper_sid

-- this block determines whether dbms_system.ksdwrt is accessible to us -- dbms_describe is required as all_procedures/all_objects may show this object -- even if its not executable by us (thanks to o7_dictionary_accessibility=false ) var v var x declare o p l a dty def inout len prec scal rad spa tmp begin begin execute immediate 'select count(*) from x$kcbwh where rownum = 1' into t mp; :x:= ' '; -- x$ tables are accessible, so dont comment any lines out exception when others then null; end; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.varchar2_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; sys.dbms_describe.number_table; number; varchar2(100) varchar2(10)

sys.dbms_describe.describe_procedure( 'DBMS_SYSTEM.KSDWRT', null, null, o, p, l, a, dty, def, inout, len, prec, scal, rad, spa ); -- we never get to following statement if dbms_system is not accessible -- as sys.dbms_describe will raise an exception :v:= '-- dbms_system is accessible'; exception when others then null; end; / -- this is here for a reason -- im extracting the first word of the snapper_sid (if its a complex expression, not just a single SID) -- by relying on how DEF and & assignment treat spaces in strings def ssid_begin=&snapper_sid select snapper_sid from ( select case when trim(lower('&ssid_begin')) like 'sid=%' then trim(replace('&ssi d_begin','sid=','')) when trim(lower('&ssid_begin')) like 'user=%' then 'select sid from v$session where lower(username) like '''||lower(trim(replace('&ssid_begin','user =','')))||'''' when trim(lower('&ssid_begin')) like 'username=%' then 'select sid f rom v$session where lower(username) like '''||lower(trim(replace('&ssid_begin',' username=','')))||'''' when trim(lower('&ssid_begin')) like 'machine=%' then 'select sid fr om v$session where lower(machine) like '''||lower(trim(replace('&ssid_begin','ma chine=','')))||'''' when trim(lower('&ssid_begin')) like 'program=%' then 'select sid fr om v$session where lower(program) like '''||lower(trim(replace('&ssid_begin','pr ogram=','')))||'''' when trim(lower('&ssid_begin')) like 'service=%' then 'select sid fr om v$session where lower(service_name) like '''||lower(trim(replace('&ssid_begin ','service=','')))||'''' when trim(lower('&ssid_begin')) like 'module=%' then 'select sid fro m v$session where lower(module) like '''||lower(trim(replace('&ssid_begin','modu le=','')))||'''' when trim(lower('&ssid_begin')) like 'action=%' then 'select sid fro m v$session where lower(action) like '''||lower(trim(replace('&ssid_begin','acti on=','')))||'''' when trim(lower('&ssid_begin')) like 'osuser=%' then 'select sid fro m v$session where lower(osuser) like '''||lower(trim(replace('&ssid_begin','osus er=','')))||'''' when trim(lower('&ssid_begin')) like 'client_id=%' then 'select sid from v$session where lower(client_identifier) like '''||lower(trim(replace('&ssi d_begin','client_id=','')))||'''' when trim(lower('&ssid_begin')) like 'spid=%' then 'select sid from v$session where paddr in (select addr from v$process where spid in ('||lower(tri m(replace('&ssid_begin','spid=','')))||'))' when trim(lower('&ssid_begin')) like 'ospid=%' then 'select sid from v$session where paddr in (select addr from v$process where spid in ('||lower(tr im(replace('&ssid_begin','ospid=','')))||'))' when trim(lower('&ssid_begin')) like 'pid=%' then 'select sid from v

$session where paddr in (select addr from v$process where spid in ('||lower(trim (replace('&ssid_begin','pid=','')))||'))' when trim(lower('&ssid_begin')) like 'qcsid=%' then 'select sid from v$px_session where qcsid in ('||lower(trim(replace('&ssid_begin','qcsid=',''))) ||')' when trim(lower('&ssid_begin')) like 'qc=%' then 'select sid from v$ px_session where qcsid in ('||lower(trim(replace('&ssid_begin','qc=','')))||')' when trim(lower('&ssid_begin')) = 'all' then 'select sid from v$sess ion' when trim(lower('&ssid_begin')) = 'bg' then 'select sid from v$sessi on where type=''BACKGROUND''' when trim(lower('&ssid_begin')) = 'fg' then 'select sid from v$sessi on where type=''USER''' when trim(lower('&ssid_begin')) = 'lgwr' then 'select sid from v$ses sion where program like ''%(LGWR)%''' when trim(lower('&ssid_begin')) = 'dbwr' then 'select sid from v$ses sion where program like ''%(DBW%)%''' when trim(lower('&ssid_begin')) like 'select%' then null when trim(lower('&ssid_begin')) like 'with%' then null else null end snapper_sid -- put the result back to snapper_sid sqlplus value (if its not null) from dual ) where snapper_sid is not null -- snapper_sid sqlplus variable value will not be re placed if this query doesnt return any rows / -- this query populates some sqlplus variables required for dynamic compilation used below with mod_banner as ( select replace(banner,'9.','09.') banner from v$version where rownum = 1 ) select decode(substr(banner, instr(banner, 'Release ')+8,2), '09', '--', '') snappe r_ora10lower, decode(substr(banner, instr(banner, 'Release ')+8,2), '09', '', '--') snapp er_ora9, decode(substr(banner, instr(banner, 'Release ')+8,1), '1', '', '--') snapp er_ora10higher, CASE WHEN substr(banner, instr(banner, 'Release ')+8,2) >= '11' THEN '' ELSE '--' END snapper_ora11higher, CASE WHEN substr(banner, instr(banner, 'Release ')+8,2) < '11' THEN '' ELSE '--' END snapper_ora11lower, nvl(:v, '/* dbms_system is not accessible') dbms_system_accessible, nvl(:x, '--') x_accessible, case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) >= '10.2' then '' else '--' end yes_blk_ inst, case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) >= '10.2' then '--' else '' end no_blk_i nst,

case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) >= '10.2.0.3' then '' else '--' end yes_plsq l_obj_id, case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) >= '10.2.0.3' then '--' else '' end no_plsql _obj_id, case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) < '09.2.0.7' then '' else '--' end snapper_o ra9206lower, case when substr( banner, instr(banner, 'Release ')+8, instr(substr(banner,i nstr(banner,'Release ')+8),' ') ) >= '09.2.0.7' then '' else '--' end snapper_ ora9207higher from mod_banner / set termout on serveroutput on size 1000000 format wrapped prompt Sampling SID &4 with interval &snapper_sleep seconds, taking &snapper_cou nt snapshots... -- main() -- let the Snapping start!!! declare -- Snapper start -- forward declarations procedure output(p_txt in varchar2); procedure fout; function tptformat( p_num in number, p_stype in varchar2 default 'STAT', p_precision in number default 2, p_base in number default 10, p_grouplen in number default 3 ) return varchar2; function getopt( p_parvalues in varchar2, p_extract in varchar2, p_delim in varchar2 default ',' ) return varchar2; -- type, constant, variable declarations -- trick for holding 32bit UNSIGNED event and stat_ids in 32bit SIGNED PLS_I NTEGER pls_adjust constant number(10,0) := power(2,31) - 1; type srec is record (stype varchar2(4), sid number, statistic# number, value number, event_count number ); type stab is table of srec index by pls_integer; s1 stab; s2 stab; type snrec is record (stype varchar2(4), statistic# number, name varchar2(10 0)); type sntab is table of snrec index by pls_integer; sn_tmp sntab; sn sntab;

&_IF_ORA10_OR_HIGHER nteger;

type sestab is table of v$session%rowtype index by pls_i

--For ORA9 we can't just declare this with a table type, since we need to join V $SESSION with V$SESSION_WAIT &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 TYPE sestab_rec IS RECORD ( SADDR SID SERIAL# AUDSID PADDR USER# USERNAME COMMAND OWNERID TADDR LOCKWAIT STATUS SERVER SCHEMA# SCHEMANAME OSUSER PROCESS MACHINE TERMINAL PROGRAM TYPE SQL_ADDRESS SQL_HASH_VALUE PREV_SQL_ADDR PREV_HASH_VALUE MODULE MODULE_HASH ACTION ACTION_HASH CLIENT_INFO FIXED_TABLE_SEQUENCE ROW_WAIT_OBJ# ROW_WAIT_FILE# ROW_WAIT_BLOCK# ROW_WAIT_ROW# LOGON_TIME LAST_CALL_ET PDML_ENABLED FAILOVER_TYPE FAILOVER_METHOD FAILED_OVER RESOURCE_CONSUMER_GROUP PDML_STATUS PDDL_STATUS PQ_STATUS CURRENT_QUEUE_DURATION CLIENT_IDENTIFIER SID2 SEQ# EVENT P1TEXT P1 P1RAW RAW(8), NUMBER, NUMBER, NUMBER, RAW(8), NUMBER, VARCHAR2(30), NUMBER, NUMBER, VARCHAR2(16), VARCHAR2(16), VARCHAR2(8), VARCHAR2(9), NUMBER, VARCHAR2(30), VARCHAR2(30), VARCHAR2(12), VARCHAR2(64), VARCHAR2(30), VARCHAR2(64), VARCHAR2(10), RAW(8), NUMBER, RAW(8), NUMBER, VARCHAR2(48), NUMBER, VARCHAR2(32), NUMBER, VARCHAR2(64), NUMBER, NUMBER, NUMBER, NUMBER, NUMBER, DATE, NUMBER, VARCHAR2(3), VARCHAR2(13), VARCHAR2(10), VARCHAR2(3), VARCHAR2(32), VARCHAR2(8), VARCHAR2(8), VARCHAR2(8), NUMBER, VARCHAR2(64), NUMBER, NUMBER, VARCHAR2(64), VARCHAR2(64), NUMBER, RAW(8),

&_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9

P2TEXT P2 P2RAW P3TEXT P3 P3RAW WAIT_TIME SECONDS_IN_WAIT STATE );

VARCHAR2(64), NUMBER, RAW(8), VARCHAR2(64), NUMBER, RAW(8), NUMBER, NUMBER, VARCHAR2(19)

type sestab is table of sestab_rec index by pls_integer; sestab; sestab;

g_sessions g_empty_sessions lue

type hc_tab is table of number index by pls_integer; -- index is sql hash va type ses_hash_tab is table of hc_tab index by pls_integer; -- index is SID g_ses_hash_tab ses_hash_tab; g_empty_ses_hash_tab ses_hash_tab; -- dbms_debug_vc2coll is a built-in collection present in every oracle db g_ash sys.dbms_debug_vc2coll := new sys.dbms_debug_vc2coll(); g_empty_ash sys.dbms_debug_vc2coll := new sys.dbms_debug_vc2coll(); g_ash_samples_taken number := 0; g_count_statname number; g_count_eventname number; g_mysid i number; a number; b number; c number; delta number; evcnt number; changed_values number; pagesize number:=99999999999999; missing_values_s1 number := 0; missing_values_s2 number := 0; disappeared_sid number := 0; lv_curr_sid number := 0; -- used for determining whether to print an e mpty line between session stats d1 date; d2 date; ash_date1 date; ash_date2 date; lv_gather varchar2(1000); gv_header_string varchar2(1000); lv_data_string varchar2(1000); lv_ash lv_stats varchar2(1000); varchar2(1000); number;

gather_stats gather_ash

number := 0; number := 0;

-- CONFIGURABLE STUFF --- this sets what are the default ash sample TOP reporting group by colu mns &_IF_ORA10_OR_HIGHER g_ash_columns ild_number + event + wait_class'; &_IF_ORA10_OR_HIGHER g_ash_columns1 ass'; &_IF_ORA10_OR_HIGHER g_ash_columns2 &_IF_ORA10_OR_HIGHER g_ash_columns3 + plsql_subprogram_id + sql_id'; &_IF_ORA9 g_ash_columns + event'; &_IF_ORA9 g_ash_columns1 &_IF_ORA9 g_ash_columns2 value'; &_IF_ORA9 g_ash_columns3 + plsql_subprogram_id + sql_hash_value'; -- output column output_header output_username output_sid output_time tart output_seconds number t (shown in footer of each snapshot too) output_stype number IT,STAT,TIME,ENQG,LATG,...) output_sname number output_delta number output_delta_s number ed to per second output_hdelta number ta output_hdelta_s number ta normalized to per second output_percent number ime/samples output_eventcnt number output_eventcnt_s number output_eventavg number ion &_IF_ORA9206_OR_LOWER output_pcthist number isual bar (histogram) -- 9.2.0.6 or lower - does not &_IF_ORA9207_OR_HIGHER output_pcthist number isual bar (histogram) -- Histograms seem to work for -- column widths in ASH report output w_sid number := 6; w_username number := 20; w_machine number := 20; w_terminal number := 20; := 0; -- seconds in snapsho := 1; -- statistic type (WA := 1; -- statistic name := 1; -- raw delta := 0; -- raw delta normaliz := 0; -- human readable del := 1; -- human readable del := 1; -- percent of total t := 1; -- wait event count := 1; -- wait event count := 1; -- average wait durat := 0; -- percent of total v work - jbj2 := 1; -- percent of total v me on 9.2.0.7 + - JBJ2) varchar2(1000) := 'sql_id + sql_ch varchar2(1000) := 'event + wait_cl varchar2(1000) := 'sid + sql_id'; varchar2(1000) := 'plsql_object_id varchar2(1000) := 'sql_hash_value varchar2(1000) := 'event'; varchar2(1000) := 'sid + sql_hash_ varchar2(1000) := 'plsql_object_id configuration number := 0; number := 1; number := 1; number := 0;

-----

1=true 0=false v$session.username sid time of snapshot s

w_program w_event w_wait_class w_state w_p1 w_p2 w_p3 w_row_wait_obj# w_row_wait_file# w_row_wait_block# w_row_wait_row# w_blocking_session_status w_blocking_instance w_blocking_session w_sql_hash_value w_sql_id w_sql_child_number 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 -- END CONFIGURABLE STUFF --

number number number number number number number number number number number number number number number number number number number number number number number number number

:= := := := := := := := := := := := := := := := := := := := := := := := :=

25; 35; 15; 8; 20; 20; 20; 10; 6; 10; 6; 15; 12; 12; 12; 15; 9; 10; 10; 10; 10; 25; 25; 25; 25;

number := 7;

-- constants for ash collection extraction from the vc2 collection s_sid constant number := 1 ; s_username constant number := 2 ; s_machine constant number := 3 ; s_terminal constant number := 4 ; s_program constant number := 5 ; s_event constant number := 6 ; s_wait_class constant number := 7 ; s_state constant number := 8 ; s_p1 constant number := 9 ; s_p2 constant number := 10 ; s_p3 constant number := 11 ; s_row_wait_obj# constant number := 12 ; s_row_wait_file# constant number := 13 ; s_row_wait_block# constant number := 14 ; s_row_wait_row# constant number := 15 ; s_blocking_session_status constant number := 16 ; s_blocking_instance constant number := 17 ; s_blocking_session constant number := 18 ; s_sql_hash_value constant number := 19 ; s_sql_id constant number := 20 ; s_sql_child_number constant number := 21 ; s_plsql_entry_object_id constant number := 22 ; s_plsql_entry_subprogram_id constant number := 23 ; s_plsql_object_id constant number := 24 ; s_plsql_subprogram_id constant number := 25 ; s_module constant number := 26 ; s_action constant number := 27 ; s_client_identifier constant number := 28 ; s_service_name constant number := 29 ;

-- constants for ash collection reporting, which columns to show in report c_sid constant number := power(2, s_sid ); c_username constant number := power(2, s_username ); c_machine constant number := power(2, s_machine ); c_terminal constant number := power(2, s_terminal ); c_program constant number := power(2, s_program ); c_event constant number := power(2, s_event ); c_wait_class constant number := power(2, s_wait_class ); c_state constant number := power(2, s_state ); c_p1 constant number := power(2, s_p1 ); c_p2 constant number := power(2, s_p2 ); c_p3 constant number := power(2, s_p3 ); c_row_wait_obj# constant number := power(2, s_row_wait_obj# ); c_row_wait_file# constant number := power(2, s_row_wait_file# ); c_row_wait_block# constant number := power(2, s_row_wait_block# ); c_row_wait_row# constant number := power(2, s_row_wait_row# ); c_blocking_session_status constant number := power(2, s_blocking_sessio n_status ); c_blocking_instance constant number := power(2, s_blocking_instan ce ); c_blocking_session constant number := power(2, s_blocking_sessio n ); c_sql_hash_value constant number := power(2, s_sql_hash_value ); c_sql_id constant number := power(2, s_sql_id ); c_sql_child_number constant number := power(2, s_sql_child_numbe r ); c_plsql_entry_object_id constant number := power(2, s_plsql_entry_obj ect_id ); c_plsql_entry_subprogram_id constant number := power(2, s_plsql_entry_sub program_id); c_plsql_object_id constant number := power(2, s_plsql_object_id ); c_plsql_subprogram_id constant number := power(2, s_plsql_subprogra m_id ); c_module constant number := power(2, s_module ); c_action constant number := power(2, s_action ); c_client_identifier constant number := power(2, s_client_identifi er ); c_service_name constant number := power(2, s_service_name );

-- bitfield specifying which columns to group by in sampled session activity (ASH) g_ash_grouping number := 63; -- test

/*---------------------------------------------------- proc for outputting data to trace or dbms_output ---------------------------------------------------*/ procedure output(p_txt in varchar2) is begin if (getopt('&snapper_options', 'out') is not null) or (getopt('&snapper_options', 'out') is null and getopt('&snapper_optio ns', 'trace') is null) then dbms_output.put_line(p_txt); end if; -- The block below is a sqlplus trick for conditionally commenting out P L/SQL code &_IF_DBMS_SYSTEM_ACCESSIBLE if getopt('&snapper_options', 'trace') is not null then sys.dbms_system.ksdwrt(1, p_txt); sys.dbms_system.ksdfls; end if; -- */ end; -- output /*---------------------------------------------------- proc for outputting data, utilizing global vars ---------------------------------------------------*/ procedure fout is l_output_username VARCHAR2(100); begin --if s2(b).stype='WAIT' then output( 'DEBUG WAIT ' || sn(s2(b).statistic#) .name || ' ' || delta ); end if; --output( 'DEBUG, Entering fout(), b='||to_char(b)||' sn(s2(b).statistic#= '||s2(b).statistic# ); --output( 'DEBUG, In fout(), a='||to_char(a)||' b='||to_char(b)||' s1.coun t='||s1.count||' s2.count='||s2.count||' s2.count='||s2.count); if output_username = 1 then begin l_output_username := nvl( g_sessions(s2(b).sid).username, substr (g_sessions(s2(b).sid).program, instr(g_sessions(s2(b).sid).program,'(')) ); exception when no_data_found then l_output_username := 'error'; when others then raise; end; end if; output( CASE WHEN output_header = 1 THEN 'SID= ' END || CASE WHEN output_sid = 1 THEN to_char(s2(b).sid,'999999' )||', ' END || CASE WHEN output_username = 1 THEN rpad(CASE s2(b).sid WHEN 1 THEN ' ' ELSE NVL(l_output_username, ' ') END, 10)||', ' END || CASE WHEN output_time = 1 THEN to_char(d1, 'YYYYMMDD HH24 :MI:SS')||', ' END

|| CASE WHEN output_seconds = 1 THEN to_char(case (d2-d1) when 0 then &snapper_sleep else (d2-d1) * 86400 end, '9999999')||', ' END || CASE WHEN output_stype = 1 THEN s2(b).stype||', ' END || CASE WHEN output_sname = 1 THEN rpad(sn(s2(b).statistic#). name, 58, ' ')||', ' END || CASE WHEN output_delta = 1 THEN to_char(delta, '9999999999 99')||', ' END || CASE WHEN output_delta_s = 1 THEN to_char(delta/(case (d2-d1 ) when 0 then &snapper_sleep else (d2-d1) * 86400 end),'999999999')||', ' END || CASE WHEN output_hdelta = 1 THEN lpad(tptformat(delta, s2(b ).stype), 10, ' ')||', ' END || CASE WHEN output_hdelta_s = 1 THEN lpad(tptformat(delta/(case (d2-d1) when 0 then &snapper_sleep else (d2-d1)* 86400 end ), s2(b).stype), 10, ' ')||', ' END || CASE WHEN output_percent = 1 THEN CASE WHEN s2(b).stype IN ( 'TIME','WAIT') THEN to_char(delta/CASE (d2-d1) WHEN 0 THEN &snapper_sleep ELSE ( d2-d1) * 86400 END / 10000, '9999.9')||'%' ELSE ' ' END END||', ' || CASE WHEN output_pcthist = 1 THEN CASE WHEN s2(b).stype IN ( 'TIME','WAIT') THEN rpad(rpad('[', ceil(round(delta/CASE (d2-d1) WHEN 0 THEN &sn apper_sleep ELSE (d2-d1) * 86400 END / 100000,1))+1, CASE WHEN s2(b).stype IN (' WAIT') THEN 'W' WHEN sn(s2(b).statistic#).name = 'DB CPU' THEN '@' ELSE '#' END) ,11,' ')||']' ELSE ' ' END END||', ' || CASE WHEN output_eventcnt = 1 THEN CASE WHEN s2(b).stype IN ( 'WAIT') THEN to_char(evcnt, '99999999') ELSE ' ' END END||', ' || CASE WHEN output_eventcnt_s = 1 THEN CASE WHEN s2(b).stype IN ( 'WAIT') THEN lpad(tptformat((evcnt / case (d2-d1) when 0 then &snapper_sleep els e (d2-d1)* 86400 end ), 'STAT' ), 10, ' ') ELSE ' ' END END||', ' || CASE WHEN output_eventavg = 1 THEN CASE WHEN s2(b).stype IN ( 'WAIT') THEN lpad(tptformat(delta / CASE WHEN evcnt = 0 THEN 1 ELSE evcnt END, s 2(b).stype), 10, ' ') ELSE ' ' END END ); end; /*---------------------------------------------------- function for converting large numbers to human-readable format ---------------------------------------------------*/ function tptformat( p_num in number, p_stype in varchar2 default 'STAT', p_precision in number default 2, p_base in number default 10, -- for KiB/MiB formattin g use p_grouplen in number default 3 -- p_base=2 and p_groupl en=10 ) return varchar2 is begin if p_num = 0 then return '0'; end if; if p_stype in ('WAIT','TIME') then return round( p_num / power( p_base , trunc(log(p_base,abs(p_num)))-trunc( mod(log(p_base,abs(p_num)),p_grouplen)) ), p_precision ) || case trunc(log(p_base,abs(p_num)))-trunc(mod(log(p_base,abs(p _num)),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,abs(p_nu m)))-trunc(mod(log(p_base,abs(p_num)),p_grouplen)) )||' us' end; else return round( p_num / power( p_base , trunc(log(p_base,abs(p_num)))-trunc( mod(log(p_base,abs(p_num)),p_grouplen)) ), p_precision ) || case trunc(log(p_base,abs(p_num)))-trunc(mod(log(p_base,abs(p _num)),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' when p_grouplen*5 then 'P' when p_grouplen*6 then 'E' else '*'||p_base||'^'||to_char( trunc(log(p_base,abs(p_nu m)))-trunc(mod(log(p_base,abs(p_num)),p_grouplen)) ) end; end if; end; -- tptformat /*---------------------------------------------------- simple function for parsing arguments from parameter string ---------------------------------------------------*/ function getopt( p_parvalues in varchar2, p_extract in varchar2, p_delim in varchar2 default ',' ) return varchar2 is ret varchar(1000) := NULL; begin -- dbms_output.put('p_parvalues = ['||p_parvalues||'] ' ); -- dbms_output.put('p_extract = ['||p_extract||'] ' ); if lower(p_parvalues) like lower(p_extract)||'%' or lower(p_parvalues) like '%'||p_delim||lower(p_extract)||'%' then ret := nvl ( substr(p_parvalues, instr(p_parvalues, p_extract)+length(p_extract), case instr( substr(p_parvalues, instr(p_parvalues, p_extract)+length (p_extract)

) , p_delim ) when 0 then length(p_parvalues) else instr( substr(p_parvalues, instr(p_parvalues, p_extract)+length (p_extract) ) , p_delim ) - 1 end ) , chr(0) -- in case parameter was specified but with no valu e ); else ret := null; -- no parameter found end if; -- dbms_output.put_line('ret = ['||replace(ret,chr(0),'\0')||']'); return ret; end; -- getopt /*---------------------------------------------------- proc for getting session list with username, osuser, machine etc ---------------------------------------------------*/ procedure get_sessions is tmp_sessions sestab; begin select &_IF_ORA9

s.SADDR

&_IF_ORA9 , s.SID &_IF_ORA9 , s.SERIAL# &_IF_ORA9 , s.AUDSID &_IF_ORA9 , s.PADDR &_IF_ORA9 , s.USER# &_IF_ORA9 , s.USERNAME &_IF_ORA9 , s.COMMAND &_IF_ORA9 , s.OWNERID &_IF_ORA9 , s.TADDR &_IF_ORA9 , s.LOCKWAIT &_IF_ORA9 , s.STATUS

&_IF_ORA9 , s.SERVER &_IF_ORA9 , s.SCHEMA# &_IF_ORA9 , s.SCHEMANAME &_IF_ORA9 , s.OSUSER &_IF_ORA9 , s.PROCESS &_IF_ORA9 , s.MACHINE &_IF_ORA9 , s.TERMINAL &_IF_ORA9 , CASE WHEN s.PROGRAM = 'ORACLE.EXE' THEN '('| |bg.name||')' ELSE s.program END program &_IF_ORA9 , s.TYPE &_IF_ORA9 , s.SQL_ADDRESS &_IF_ORA9 , s.SQL_HASH_VALUE &_IF_ORA9 , s.PREV_SQL_ADDR &_IF_ORA9 , s.PREV_HASH_VALUE &_IF_ORA9 , s.MODULE &_IF_ORA9 , s.MODULE_HASH &_IF_ORA9 , s.ACTION &_IF_ORA9 , s.ACTION_HASH &_IF_ORA9 , s.CLIENT_INFO &_IF_ORA9 , s.FIXED_TABLE_SEQUENCE &_IF_ORA9 , s.ROW_WAIT_OBJ# &_IF_ORA9 , s.ROW_WAIT_FILE# &_IF_ORA9 , s.ROW_WAIT_BLOCK# &_IF_ORA9 , s.ROW_WAIT_ROW# &_IF_ORA9 , s.LOGON_TIME &_IF_ORA9 , s.LAST_CALL_ET &_IF_ORA9 , s.PDML_ENABLED &_IF_ORA9 , s.FAILOVER_TYPE &_IF_ORA9 , s.FAILOVER_METHOD &_IF_ORA9 , s.FAILED_OVER

&_IF_ORA9 , s.RESOURCE_CONSUMER_GROUP &_IF_ORA9 , s.PDML_STATUS &_IF_ORA9 , s.PDDL_STATUS &_IF_ORA9 , s.PQ_STATUS &_IF_ORA9 , s.CURRENT_QUEUE_DURATION &_IF_ORA9 , s.CLIENT_IDENTIFIER &_IF_ORA9 , sw.sid SID2 &_IF_ORA9 , sw.SEQ# &_IF_ORA9 , sw.EVENT &_IF_ORA9 , sw.P1TEXT &_IF_ORA9 , sw.P1 &_IF_ORA9 , sw.P1RAW &_IF_ORA9 , sw.P2TEXT &_IF_ORA9 , sw.P2 &_IF_ORA9 , sw.P2RAW &_IF_ORA9 , sw.P3TEXT &_IF_ORA9 , sw.P3 &_IF_ORA9 , sw.P3RAW &_IF_ORA9 , sw.WAIT_TIME &_IF_ORA9 , sw.SECONDS_IN_WAIT &_IF_ORA9 , sw.STATE &_IF_ORA10_OR_HIGHER * bulk collect into tmp_sessions from v$session s, v$session_wait sw, v$bgprocess bg, v$process

&_IF_ORA9 p &_IF_ORA10_OR_HIGHER

v$session where &_IF_ORA9 s.sid in (&snapper_sid) and s.sid=sw.sid and p.addr = s.p addr and s.paddr = bg.paddr(+); &_IF_ORA10_OR_HIGHER sid in (&snapper_sid); g_sessions := g_empty_sessions; for i in 1..tmp_sessions.count loop g_sessions(tmp_sessions(i).sid) := tmp_sessions(i); end loop;

end; -- get_sessions /*---------------------------------------------------- function for getting session list with username, osuser, machine etc -- 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 sestab; l_return_sessions sestab; begin select s.*,sw.* * bulk collect into tmp_sessions from &_IF_ORA9 v$session s, v$session_wait sw &_IF_ORA10_OR_HIGHER v$session where &_IF_ORA9 s.sid in (&snapper_sid) and s.sid=sw.sid; &_IF_ORA10_OR_HIGHER sid in (&snapper_sid); &_IF_ORA9 &_IF_ORA10_OR_HIGHER for i in 1..tmp_sessions.count loop --output('get_sessions i='||i||' sid='||tmp_sessions(i).sid); l_return_sessions(tmp_sessions(i).sid) := tmp_sessions(i); end loop; return l_return_sessions; end; -- get_sessions

/*---------------------------------------------------- functions for extracting and converting v$session -- records to varchar2 ---------------------------------------------------*/ function sitem(p in varchar2) return varchar2 as begin return '<'||translate(p, '<>', '__')||'>'; end; -- sitem varchar2 function sitem(p in number) return varchar2 as begin return '<'||to_char(p)||'>'; end; -- sitem number function sitem(p in date) return varchar2 as begin return '<'||to_char(p, 'YYYY-MM-DD HH24:MI:SS')||'>'; end; -- sitem date function sitem_raw(p in raw) return varchar2 as begin return '<'||upper(rawtohex(p))||'>'; end; -- sitem_raw

/*---------------------------------------------------- proc for resetting the snapper ash array ---------------------------------------------------*/ procedure reset_ash is begin g_ash_samples_taken := 0; -- clear g_ash g_ash := new sys.dbms_debug_vc2coll(); end; -- reset_ash /*---------------------------------------------------- proc for getting ash style samples from v$session -- (and v$session_wait in 9i) ---------------------------------------------------*/ procedure extract_ash is ash_i number; &_IF_ORA10_OR_HIGHER s v$session%rowtype; &_IF_ORA9 s sestab_rec; begin -- keep track how many times we sampled v$session so we could calculate a verages later on g_ash_samples_taken := g_ash_samples_taken + 1; --output('g_sessions.count='||g_sessions.count); ash_i := g_sessions.first; while ash_i is not null loop s := g_sessions(ash_i); -- only extract active sessions, TODO: get rid of wait_class for 9i co mpatibility if -- active, on cpu (s.status = 'ACTIVE' and s.state != 'WAITING' and s.sid != g_mysid ) or -- active, waiting for non-idle wait &_IF_ORA10_OR_HIGHER (s.status = 'ACTIVE' and s.state = 'WAITING' and s.wait_cl ass != 'Idle' and s.sid != g_mysid) &_IF_ORA9 (s.status = 'ACTIVE' and s.state = 'WAITING' &_IF_ORA9 -- Use a fixed list of idle wait events on 9i, since wait _class is not available &_IF_ORA9 and lower(s.event) not in ( &_IF_ORA9 'smon timer' -- idle events from 9i &_IF_ORA9 , 'pmon timer' &_IF_ORA9 , 'rdbms ipc message' &_IF_ORA9 , 'null event' &_IF_ORA9 , 'parallel query dequeue' &_IF_ORA9 , 'pipe get' &_IF_ORA9 , 'client message' &_IF_ORA9 , 'sql*net message from client' &_IF_ORA9 , 'dispatcher timer' &_IF_ORA9 , 'virtual circuit status' &_IF_ORA9 , 'lock manager wait for remote message' &_IF_ORA9 , 'px idle wait' &_IF_ORA9 , 'px deq: execution msg' &_IF_ORA9 , 'px deq: table q normal' &_IF_ORA9 , 'wakeup time manager' &_IF_ORA9 , 'slave wait' &_IF_ORA9 , 'i/o slave wait'

&_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 hannels' &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 leanup' &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9

, , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

'jobq slave wait' 'null event' 'gcs remote message' 'gcs for action' 'ges remote message' 'queue messages' 'pmon timer' -- from 11.2.0.2 v$event_name 'vktm logical idle wait' 'vktm init wait for gsga' 'iorm scheduler slave idle wait' 'rdbms ipc message' 'i/o slave wait' 'vkrm idle' 'wait for unread message on broadcast channel' 'wait for unread message on multiple broadcast c 'class slave wait' 'ksv master wait' 'ping' 'watchdog main loop' 'diag idle wait' 'ges remote message' 'gcs remote message' 'heartbeat monitor sleep' 'gcr sleep' 'sga: mman sleep for component shrink' 'mrp redo arrival' 'lns async archive log' 'lns async dest activation' 'lns async end of log' 'simulated log write delay' 'lgwr real time apply sync' 'parallel recovery slave idle wait' 'logminer builder: idle' 'logminer builder: branch' 'logminer preparer: idle' 'logminer reader: log (idle)' 'logminer reader: redo (idle)' 'logminer client: transaction' 'logminer: other' 'logminer: activate' 'logminer: reset' 'logminer: find session' 'logminer: internal' 'logical standby apply delay' 'parallel recovery coordinator waits for slave c 'parallel recovery control message reply' 'parallel recovery slave next change' 'px deq: txn recovery start' 'px deq: txn recovery reply' 'fbar timer' 'smon timer' 'px deq: metadata update' 'space manager: slave idle wait' 'px deq: index merge reply' 'px deq: index merge execute' 'px deq: index merge close' 'px deq: kdcph_mai' 'px deq: kdcphc_ack'

&_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 nup tasks' &_IF_ORA9 &_IF_ORA9 ol' &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9 &_IF_ORA9

, , , , , , , , , , , , , , , , , , , , , , , , , , , , , ,

'shared server idle wait' 'dispatcher timer' 'cmon timer' 'pool server timer' 'jox jit process sleep' 'jobq slave wait' 'pipe get' 'px deque wait' 'px idle wait' 'px deq: join ack' 'px deq credit: need buffer' 'px deq credit: send blkd' 'px deq: msg fragment' 'px deq: parse reply' 'px deq: execute reply' 'px deq: execution msg' 'px deq: table q normal' 'px deq: table q sample' 'streams fetch slave: waiting for txns' 'streams: waiting for messages' 'streams capture: waiting for archive log' 'single-task message' 'sql*net message from client' 'sql*net vector message from client' 'sql*net vector message from dblink' 'pl/sql lock timer' 'streams aq: emn coordinator idle wait' 'emon slave idle wait' 'streams aq: waiting for messages in the queue' 'streams aq: waiting for time management or clea

, 'streams aq: delete acknowledged messages' , 'streams aq: deallocate messages from streams po , 'streams aq: qmn coordinator idle wait' , 'streams aq: qmn slave idle wait' , 'streams aq: rac qmn coordinator idle wait' , 'hs message to agent' , 'asm background timer' , 'auto-sqltune: wait graph update' , 'wcr: replay client notify' , 'wcr: replay clock' , 'wcr: replay paused' , 'js external job' , 'cell worker idle') and s.sid != g_mysid)

then --output('extract_ash: i='||i||' sid='||s.sid||' hv='||s.sql_hash_v alue||' sqlid='||s.sql_id); -- if not actually waiting for anything, clear the past wait event details if s.state != 'WAITING' then s.state:='ON CPU'; s.event:='ON CPU'; &_IF_ORA10_OR_HIGHER s.wait_class:='ON CPU'; --TODO: What do we need to do for 9 i here? s.p1:=NULL; s.p2:=NULL; s.p3:=NULL;

end if; g_ash.extend; -- max length 1000 bytes (due to dbms_debug_vc2coll) g_ash(g_ash.count) := substr( sitem(s.sid) -- 1 ||sitem(s.username) -- 2 -- 30 byte s ||sitem(s.machine) s ||sitem(s.terminal) s ||sitem(s.program) s ||sitem(s.event) s &_IF_ORA10_OR_HIGHER s, 10g+ &_IF_ORA9 ||sitem(s.wait_class) ||sitem('N/A') ||sitem(s.state) ||sitem(s.p1) ||sitem(s.p2) ||sitem(s.p3) ||sitem(s.row_wait_obj#) ||sitem(s.row_wait_file#) ||sitem(s.row_wait_block#) ||sitem(s.row_wait_row#) ||sitem(s.blocking_session_status) ||sitem('N/A') ||sitem('N/A') ||sitem(s.blocking_instance) ||sitem(s.blocking_session) ||sitem('N/A') -- 7 -- 64 byte ---------------7 8 9 10 11 12 13 14 15 16 16 17 17 18 18 -- 6 -- 64 byte -- 5 -- 48 byte -- 4 -- 30 byte -- 3 -- 64 byte

&_IF_ORA10_OR_HIGHER &_IF_ORA9 -- 16 &_NO_BLK_INST &_YES_BLK_INST &_IF_ORA10_OR_HIGHER &_IF_ORA9

-- 10g+ -- 10g+ ----10gR2+ 10gR2+ 10g+ 10g+

||sitem(s.sql_hash_value) &_IF_ORA10_OR_HIGHER ||sitem(s.sql_id) &_IF_ORA9 ||sitem(to_char(s.sql_hash_value)) t's just put hash_value into sql_id &_IF_ORA10_OR_HIGHER ||sitem(s.sql_child_number) &_IF_ORA9 ||sitem('N/A') &_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.plsql_entry_object_id) &_YES_PLSQL_OBJ_ID ||sitem(s.plsql_entry_subprogram_id) &_YES_PLSQL_OBJ_ID ||sitem(s.plsql_object_id) &_YES_PLSQL_OBJ_ID ||sitem(s.plsql_subprogram_id) ||sitem(s.module) s ||sitem(s.action) s ||sitem(s.client_identifier) s &_IF_ORA10_OR_HIGHER ||sitem(s.service_name) s, 10g+ &_IF_ORA9 ||sitem('N/A') , 1, 1000);

-- 19 -- 20 -- 20 ------------

-- 10g+ -- 9i, le

21 -- 10g+ 21 -- 10g+ 22 23 24 25 22 23 24 25 26 -- 48 byte

-- 27 -- 32 byte -- 28 -- 64 byte -- 29 -- 64 byte -- 29

end if; -- sample is of an active session ash_i := g_sessions.next(ash_i); end loop; exception when no_data_found then output('error in extract_ash(): no_data_found for item '||i); end; -- extract_ash /*---------------------------------------------------- proc for querying performance data into collections ---------------------------------------------------*/ procedure snap( p_snapdate in out date, p_stats in out stab ) is lv_include_stat nclude=' )), '%'); lv_include_latch nclude=' )), '%'); lv_include_time nclude=' )), '%'); lv_include_wait nclude=' )), '%'); begin p_snapdate := sysdate; select * bulk collect into p_stats from ( select 'STAT' stype, sid, statistic# pls_adjust statistic#, value, null event_count from v$sesstat where sid in (&snapper_sid) and (lv_gather like '%s%' or lv_gather like '%a%') and statistic# in (select /*+ no_unnest */ statistic# from v$statname where lower(name) li ke '%'||lv_include_stat||'%' &_IF_ORA10_OR_HIGHER or regexp_like (name , lv_include_stat, 'i') ) -union all select 'WAIT', sw.sid, en.event# + (select count(*) fro m v$statname) + 1 - pls_adjust, nvl(se.time_waited_micro,0) + ( decode(se.event||sw.state, sw.event||'WAITING', sw.seconds_in_wait, 0) * 1000000 ) value, total_waits event_count from v$session_wait sw, v$session_event se, v$event_name en where sw.sid = se.sid varchar2(1000) := nvl( lower(getopt('&snapper_options', 'si varchar2(1000) := nvl( lower(getopt('&snapper_options', 'li varchar2(1000) := nvl( lower(getopt('&snapper_options', 'ti varchar2(1000) := nvl( lower(getopt('&snapper_options', 'wi

and and and r like '%a%') and event_name ke '%'||lv_include_wait||'%' &_IF_ORA10_OR_HIGHER ame, lv_include_wait, 'i')

se.event = en.name se.sid in (&snapper_sid) (lv_gather like '%w%' or lv_gathe event# in (select event# from v$ where lower(name) li or regexp_like (n

) -&_IF_ORA10_OR_HIGHER union all &_IF_ORA10_OR_HIGHER select 'TIME' stype, sid, stat_id - pls _adjust statistic#, value, null event_count &_IF_ORA10_OR_HIGHER from v$sess_time_model &_IF_ORA10_OR_HIGHER where sid in (&snapper_sid) &_IF_ORA10_OR_HIGHER and (lv_gather like '%t%' or lv_gathe r like '%a%') &_IF_ORA10_OR_HIGHER and stat_id in (select stat_id from v$s ys_time_model &_IF_ORA10_OR_HIGHER where lower(stat_nam e) like '%'||lv_include_time||'%' &_IF_ORA10_OR_HIGHER or regexp_like (s tat_name, lv_include_time, 'i') &_IF_ORA10_OR_HIGHER ) -union all select 'LATG', -1 sid, l.latch# + (select count(*) from v$statn ame) + (select count(*) from v$event _name) + 1 - pls_adjust statistic#, l.gets + l.immediate_gets value, null event_count from v$latch l where (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||'%' &_IF_ORA10_OR_HIGHER or regexp_like (name, lv_include_latch, 'i') ) -&_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 union all &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 select 'BUFG', -1 sid, &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 s.indx + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from v$stat name) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from v$even t_name) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 (select count(*) from v$latc h) + &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 1 - pls_adjust statistic#, &_IF_X_ACCESSIBLE &_IF_LOWER_THAN_ORA11 s.why0+s.why1+s.why2 value, null

event_count &_IF_X_ACCESSIBLE &_IF_X_ACCESSIBLE &_IF_X_ACCESSIBLE &_IF_X_ACCESSIBLE &_IF_X_ACCESSIBLE er like '%a%')

&_IF_LOWER_THAN_ORA11 &_IF_LOWER_THAN_ORA11 &_IF_LOWER_THAN_ORA11 &_IF_LOWER_THAN_ORA11 &_IF_LOWER_THAN_ORA11

from x$kcbsw s, x$kcbwh w where s.indx = w.indx and s.why0+s.why1+s.why2 > 0 and (lv_gather like '%b%' or lv_gath -union all select 'BUFG', -1 sid, sw.indx + (select count(*) from v$stat (select count(*) from v$even (select count(*) from v$latc 1 - pls_adjust statistic#, why.why0+why.why1+why.why2+sw.ot from x$kcbuwhy why, x$kcbwh dsc, x$kcbsw sw where and and and and why.indx = dsc.indx why.why0 + why.why1 + why.why2 + dsc.indx = sw.indx why.indx = sw.indx -- deliberate cartesian join (lv_gather like '%b%' or lv_gath

&_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER name) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER t_name) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER h) + &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER her_wait value, null event_count &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER sw.other_wait > 0 &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER &_IF_X_ACCESSIBLE &_IF_ORA11_OR_HIGHER er like '%a%')

-union all select 'ENQG', -1 sid, ascii(substr(e.eq_type,1,1))*256 + ascii(substr(e.eq_type,2,1)) + (select count(*) from v$statn ame) + (select count(*) from v$event _name) + (select count(*) from v$latch ) + &_IF_X_ACCESSIBLE ) + unt from v$enqueue_stat e where (lv_gather like '%e%' or lv_gathe r like '%a%') ) snapper_stats order by sid, stype, statistic#; end snap; /*---------------------------------------------------- proc for dumping ASH data out in grouped (select count(*) from x$kcbwh 1 - pls_adjust statistic#, e.total_req# value, null event_co

-- and ordered fashion ---------------------------------------------------*/ procedure out_ash( p_ash_columns in varchar2, p_topn in number := 10 ) as -- whether to print given column or not 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 := p_row_wait_obj# number := p_row_wait_file# number := p_row_wait_block# number := p_row_wait_row# number := p_blocking_session_status number := p_blocking_instance number := p_blocking_session number := p_sql_hash_value number := p_sql_id number := p_sql_child_number number := p_plsql_entry_object_id number := p_plsql_entry_subprogram_id number := p_plsql_object_id number := p_plsql_subprogram_id number := p_module number := p_action number := p_client_identifier number := p_service_name number := ) 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 varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;

-- temporary variables for holding session details (for later formatting

o_plsql_object_id o_plsql_subprogram_id o_module o_action o_client_identifier o_service_name -- helper local vars l_ash_grouping l_output_line l_ash_header_line begin

varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); varchar2(100); number := 0; varchar2(4000); varchar2(4000);

-- bail out if no ASH samples recorded if g_ash.count = 0 then output(' <No active sessions captured during the sampling period>') ; return; end if; l_ash_header_line := 'Active%'; -- ash,ash1,ash2,ash3 parameter column group tokenizer for s in ( -- ORA9 SQL*Plus returns only a single row with CONNECT BY LEVEL; An additonal o uter SELECT * from (...) fixes this &_IF_ORA9 select * from ( SELECT LEVEL , SUBSTR ( TOKEN , DECODE(LEVEL, 1, 1, INSTR(TOKEN, DELIMITER, 1, LEVEL-1)+1) , INSTR(TOKEN, DELIMITER, 1, LEVEL) DECODE(LEVEL, 1, 1, INSTR(TOKEN, DELIMITER, 1, LEVEL-1)+1) ) TOKEN FROM ( SELECT REPLACE( LOWER(p_ash_columns) ,' ','')||'+' AS TOKEN , '+' AS DELIMITER FROM DUAL ) CONNECT BY INSTR(TOKEN, DELIMITER, 1, LEVEL)>0 &_IF_ORA9 ) ORDER BY LEVEL ASC ) loop case s.token -- actual column names in v$session when 'sid' then l_ash_grouping := l_ash_g c_sid ; l_ash_header_line := l_ash_header_line || lpad('SID' , w_sid , ' '); when 'username' then l_ash_grouping := l_ash_g c_username ; l_ash_header_line := l_ash_header_line || rpad('USERNAME' , w_username , ' '); when 'machine' then l_ash_grouping := l_ash_g c_machine ; l_ash_header_line := l_ash_header_line || rpad('MACHINE' , w_machine , ' '); when 'terminal' then l_ash_grouping := l_ash_g

rouping + ' | ' || rouping + ' | ' || rouping + ' | ' ||

rouping + c_terminal ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('TERMINAL' , w_terminal , ' '); when 'program' then l_ash_grouping := l_ash_g rouping + c_program ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PROGRAM' , w_program , ' '); when 'event' then l_ash_grouping := l_ash_g rouping + c_event ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('EVENT' , w_event , ' '); when 'wait_class' then l_ash_grouping := l_ash_g rouping + c_wait_class ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('WAIT_CLASS' , w_wait_class , ' '); when 'state' then l_ash_grouping := l_ash_g rouping + c_state ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('STATE' , w_state , ' '); when 'p1' then l_ash_grouping := l_ash_g rouping + c_p1 ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('P1' , w_p1 , ' '); when 'p2' then l_ash_grouping := l_ash_g rouping + c_p2 ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('P2' , w_p2 , ' '); when 'p3' then l_ash_grouping := l_ash_g rouping + c_p3 ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('P3' , w_p3 , ' '); 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('ROW_WAIT_OBJ#' , w_row_wait_obj# , ' '); when 'row_wait_file#' then l_ash_grouping := l_ash_g rouping + c_row_wait_file# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_FILE#' , w_row_wait_file# , ' '); when 'row_wait_block#' then l_ash_grouping := l_ash_g rouping + c_row_wait_block# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_BLOCK#' , w_row_wait_block# , ' '); when 'row_wait_row#' then l_ash_grouping := l_ash_g rouping + c_row_wait_row# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_ROW#' , w_row_wait_row# , ' '); when 'blocking_session_status' then l_ash_grouping := l_ash_g rouping + c_blocking_session_status ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION_STATUS' , w_blocking_session_status , ' '); when 'blocking_instance' then l_ash_grouping := l_ash_g rouping + c_blocking_instance ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_INSTANCE' , w_blocking_instance , ' '); when 'blocking_session' then l_ash_grouping := l_ash_g rouping + c_blocking_session ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION' , w_blocking_session , ' '); when 'sql_hash_value' then l_ash_grouping := l_ash_g rouping + c_sql_hash_value ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_HASH_VALUE' , w_sql_hash_value , ' '); when 'sql_id' then l_ash_grouping := l_ash_g rouping + c_sql_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_ID' , w_sql_id , ' '); when 'sql_child_number' then l_ash_grouping := l_ash_g rouping + c_sql_child_number ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_CHILD_NUMBER' , w_sql_child_number , ' '); 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('PLSQL_ENTRY_OBJECT_ID' , w_plsql_entry_object_id , ' '); when 'plsql_entry_subprogram_id' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_subprogram_id; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_SUBPROGRAM_ID' , w_plsql_entry_subprogram_id, ' '); when 'plsql_object_id' then l_ash_grouping := l_ash_g

rouping + c_plsql_object_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_OBJECT_ID' , w_plsql_object_id , ' '); when 'plsql_subprogram_id' then l_ash_grouping := l_ash_g rouping + c_plsql_subprogram_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_SUBPROGRAM_ID' , w_plsql_subprogram_id , ' '); when 'module' then l_ash_grouping := l_ash_g rouping + c_module ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('MODULE' , w_module , ' '); when 'action' then l_ash_grouping := l_ash_g rouping + c_action ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ACTION' , w_action , ' '); when 'client_identifier' then l_ash_grouping := l_ash_g rouping + c_client_identifier ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('CLIENT_IDENTIFIER' , w_client_identifier , ' '); when 'service_name' then l_ash_grouping := l_ash_g rouping + c_service_name ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SERVICE_NAME' , w_service_name , ' '); -- 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 ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('USERNAME' , w_username , ' '); when 'obj' then l_ash_grouping := l_ash_g rouping + c_row_wait_obj# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_OBJ#' , w_row_wait_obj# , ' '); when 'file' then l_ash_grouping := l_ash_g rouping + c_row_wait_file# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_FILE#' , w_row_wait_file# , ' '); 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_BLOCK#' , w_row_wait_block# , ' '); when 'row' then l_ash_grouping := l_ash_g rouping + c_row_wait_row# ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ROW_WAIT_ROW#' , w_row_wait_row# , ' '); when 'bss' then l_ash_grouping := l_ash_g rouping + c_blocking_session_status ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION_STATUS' , w_blocking_session_status , ' '); when 'bsi' then l_ash_grouping := l_ash_g rouping + c_blocking_instance ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_INSTANCE' , w_blocking_instance , ' '); when 'bs' then l_ash_grouping := l_ash_g rouping + c_blocking_session ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('BLOCKING_SESSION' , w_blocking_session , ' '); when 'sql' then l_ash_grouping := l_ash_g rouping + c_sql_hash_value ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_HASH_VALUE' , w_sql_hash_value , ' '); when 'sqlid' then l_ash_grouping := l_ash_g rouping + c_sql_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_ID' , w_sql_id , ' '); when 'child' then l_ash_grouping := l_ash_g rouping + c_sql_child_number ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SQL_CHILD_NUMBER' , w_sql_child_number , ' '); when 'plsql_eoid' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_object_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_OBJECT_ID' , w_plsql_entry_object_id , ' '); when 'plsql_esubpid' then l_ash_grouping := l_ash_g rouping + c_plsql_entry_subprogram_id; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_ENTRY_SUBPROGRAM_ID' , w_plsql_entry_subprogram_id, ' '); when 'plsql_oid' then l_ash_grouping := l_ash_g rouping + c_plsql_object_id ; l_ash_header_line := l_ash_header_line ||

' | ' || rpad('PLSQL_OBJECT_ID' , w_plsql_object_id , ' '); when 'plsql_subpid' then l_ash_grouping := l_ash_g rouping + c_plsql_subprogram_id ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('PLSQL_SUBPROGRAM_ID' , w_plsql_subprogram_id , ' '); when 'mod' then l_ash_grouping := l_ash_g rouping + c_module ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('MODULE' , w_module , ' '); when 'act' then l_ash_grouping := l_ash_g rouping + c_action ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('ACTION' , w_action , ' '); when 'cid' then l_ash_grouping := l_ash_g rouping + c_client_identifier ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('CLIENT_IDENTIFIER' , w_client_identifier , ' '); when 'service' then l_ash_grouping := l_ash_g rouping + c_service_name ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('SERVICE_NAME' , w_service_name , ' '); when 'wait_event' then l_ash_grouping := l_ash_g rouping + c_event ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('EVENT' , w_event , ' '); when 'wait_state' then l_ash_grouping := l_ash_g rouping + c_state ; l_ash_header_line := l_ash_header_line || ' | ' || rpad('STATE' , w_state , ' '); else null; -- raise_application_error(-20000, 'Invalid ASH column name'); end case; -- case s.token end loop; -- tokenizer output(' '); output(lpad('-',length(l_ash_header_line),'-')); output(l_ash_header_line); output(lpad('-',length(l_ash_header_line),'-')); -- this is needed for "easy" sorting and group by ops (without any custom stored object types!) for i in ( with raw_records as ( select column_value rec from table(cast(g_ash as sys.dbms_debug_vc2 coll)) ), ash_records as ( select substr(r.rec, instr(r.rec, '<', 1, 1)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 1)+1), '>')-1) sid , substr(r.rec, instr(r.rec, '<', 1, 2)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 2)+1), '>')-1) username , substr(r.rec, instr(r.rec, '<', 1, 3)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 3)+1), '>')-1) machine , substr(r.rec, instr(r.rec, '<', 1, 4)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 4)+1), '>')-1) terminal , substr(r.rec, instr(r.rec, '<', 1, 5)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 5)+1), '>')-1) program , substr(r.rec, instr(r.rec, '<', 1, 6)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 6)+1), '>')-1) event , substr(r.rec, instr(r.rec, '<', 1, 7)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 7)+1), '>')-1) wait_class , substr(r.rec, instr(r.rec, '<', 1, 8)+1, instr (substr(r.rec, instr(r.rec, '<', 1, 8)+1), '>')-1) state , substr(r.rec, instr(r.rec, '<', 1, 9)+1, instr (substr(r.rec,

instr(r.rec, '<', 1, 9)+1), '>')-1) p1 , substr(r.rec, instr(r.rec, '<', 1, 10)+1, instr instr(r.rec, '<', 1, 10)+1), '>')-1) p2 , substr(r.rec, instr(r.rec, '<', 1, 11)+1, instr instr(r.rec, '<', 1, 11)+1), '>')-1) p3 , substr(r.rec, instr(r.rec, '<', 1, 12)+1, instr instr(r.rec, '<', 1, 12)+1), '>')-1) row_wait_obj# , substr(r.rec, instr(r.rec, '<', 1, 13)+1, instr instr(r.rec, '<', 1, 13)+1), '>')-1) row_wait_file# , substr(r.rec, instr(r.rec, '<', 1, 14)+1, instr instr(r.rec, '<', 1, 14)+1), '>')-1) row_wait_block# , substr(r.rec, instr(r.rec, '<', 1, 15)+1, instr instr(r.rec, '<', 1, 15)+1), '>')-1) row_wait_row# , substr(r.rec, instr(r.rec, '<', 1, 16)+1, instr instr(r.rec, '<', 1, 16)+1), '>')-1) blocking_session_status , substr(r.rec, instr(r.rec, '<', 1, 17)+1, instr instr(r.rec, '<', 1, 17)+1), '>')-1) blocking_instance , substr(r.rec, instr(r.rec, '<', 1, 18)+1, instr instr(r.rec, '<', 1, 18)+1), '>')-1) blocking_session , substr(r.rec, instr(r.rec, '<', 1, 19)+1, instr instr(r.rec, '<', 1, 19)+1), '>')-1) sql_hash_value , substr(r.rec, instr(r.rec, '<', 1, 20)+1, instr instr(r.rec, '<', 1, 20)+1), '>')-1) sql_id , substr(r.rec, instr(r.rec, '<', 1, 21)+1, instr instr(r.rec, '<', 1, 21)+1), '>')-1) sql_child_number , substr(r.rec, instr(r.rec, '<', 1, 22)+1, instr instr(r.rec, '<', 1, 22)+1), '>')-1) plsql_entry_object_id , substr(r.rec, instr(r.rec, '<', 1, 23)+1, instr instr(r.rec, '<', 1, 23)+1), '>')-1) plsql_entry_subprogram_id , substr(r.rec, instr(r.rec, '<', 1, 24)+1, instr instr(r.rec, '<', 1, 24)+1), '>')-1) plsql_object_id , substr(r.rec, instr(r.rec, '<', 1, 25)+1, instr instr(r.rec, '<', 1, 25)+1), '>')-1) plsql_subprogram_id , substr(r.rec, instr(r.rec, '<', 1, 26)+1, instr instr(r.rec, '<', 1, 26)+1), '>')-1) module , substr(r.rec, instr(r.rec, '<', 1, 27)+1, instr instr(r.rec, '<', 1, 27)+1), '>')-1) action , substr(r.rec, instr(r.rec, '<', 1, 28)+1, instr instr(r.rec, '<', 1, 28)+1), '>')-1) client_identifier , substr(r.rec, instr(r.rec, '<', 1, 29)+1, instr instr(r.rec, '<', 1, 29)+1), '>')-1) service_name from raw_records r ) select * from ( select decode(bitand(l_ash_grouping, power(2, s_sid )), 0, chr(0), sid ) as sid , decode(bitand(l_ash_grouping, power(2, s_username )), 0, chr(0), username ) as username , decode(bitand(l_ash_grouping, power(2, s_machine )), 0, chr(0), machine ) as machine , decode(bitand(l_ash_grouping, power(2, s_terminal )), 0, chr(0), terminal ) as terminal , decode(bitand(l_ash_grouping, power(2, s_program )), 0, chr(0), program ) as program

(substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec, (substr(r.rec,

, decode(bitand(l_ash_grouping, power(2, s_event )), 0, chr(0), event ) as event , decode(bitand(l_ash_grouping, power(2, s_wait_class )), 0, chr(0), wait_class ) as wait_class , decode(bitand(l_ash_grouping, power(2, s_state )), 0, chr(0), state ) as state , decode(bitand(l_ash_grouping, power(2, s_p1 )), 0, chr(0), p1 ) as p1 , decode(bitand(l_ash_grouping, power(2, s_p2 )), 0, chr(0), p2 ) as p2 , decode(bitand(l_ash_grouping, power(2, s_p3 )), 0, chr(0), p3 ) as p3 , decode(bitand(l_ash_grouping, power(2, s_row_wait_obj# )), 0, chr(0), row_wait_obj# ) as row_wait_obj# , decode(bitand(l_ash_grouping, power(2, s_row_wait_file# )), 0, chr(0), row_wait_file# ) as row_wait_file# , decode(bitand(l_ash_grouping, power(2, s_row_wait_block# )), 0, chr(0), row_wait_block# ) as row_wait_block# , decode(bitand(l_ash_grouping, power(2, s_row_wait_row# )), 0, chr(0), row_wait_row# ) as row_wait_row# , decode(bitand(l_ash_grouping, power(2, s_blocking_session_status )), 0, chr(0), blocking_session_status ) as blocking_session_status , decode(bitand(l_ash_grouping, power(2, s_blocking_instance )), 0, chr(0), blocking_instance ) as blocking_instance , decode(bitand(l_ash_grouping, power(2, s_blocking_session )), 0, chr(0), blocking_session ) as blocking_session , decode(bitand(l_ash_grouping, power(2, s_sql_hash_value )), 0, chr(0), sql_hash_value ) as sql_hash_value , decode(bitand(l_ash_grouping, power(2, s_sql_id )), 0, chr(0), sql_id ) as sql_id , decode(bitand(l_ash_grouping, power(2, s_sql_child_number )), 0, chr(0), sql_child_number ) as sql_child_number , decode(bitand(l_ash_grouping, power(2, s_plsql_entry_object_id )), 0, chr(0), plsql_entry_object_id ) as plsql_entry_object_id d d , decode(bitand(l_ash_grouping, power(2, s_plsql_entry_subprogram_i )), 0, chr(0), plsql_entry_subprogram_id ) as plsql_entry_subprogram_i , decode(bitand(l_ash_grouping, power(2, s_plsql_object_id )), 0, chr(0), plsql_object_id ) as plsql_object_id , decode(bitand(l_ash_grouping, power(2, s_plsql_subprogram_id )), 0, chr(0), plsql_subprogram_id ) as plsql_subprogram_id

, decode(bitand(l_ash_grouping, power(2, s_module )), 0, chr(0), module ) as module , decode(bitand(l_ash_grouping, power(2, s_action )), 0, chr(0), action ) as action , decode(bitand(l_ash_grouping, power(2, s_client_identifier )), 0, chr(0), client_identifier ) as client_identifier , decode(bitand(l_ash_grouping, power(2, s_service_name )), 0, chr(0), service_name ) as service_name , count(*)/g_ash_samples_taken average_active_samples from ash_records a group by decode(bitand(l_ash_grouping, power(2, s_sid )), 0, chr(0), sid ) -- sid , decode(bitand(l_ash_grouping, power(2, s_username )), 0, chr(0), username ) -- username , decode(bitand(l_ash_grouping, power(2, s_machine )), 0, chr(0), machine ) -- machine , decode(bitand(l_ash_grouping, power(2, s_terminal )), 0, chr(0), terminal ) -- terminal , decode(bitand(l_ash_grouping, power(2, s_program )), 0, chr(0), program ) -- program , decode(bitand(l_ash_grouping, power(2, s_event )), 0, chr(0), event ) -- event , decode(bitand(l_ash_grouping, power(2, s_wait_class )), 0, chr(0), wait_class ) -- wait_class , decode(bitand(l_ash_grouping, power(2, s_state )), 0, chr(0), state ) -- state , decode(bitand(l_ash_grouping, power(2, s_p1 )), 0, chr(0), p1 ) -- p1 , decode(bitand(l_ash_grouping, power(2, s_p2 )), 0, chr(0), p2 ) -- p2 , decode(bitand(l_ash_grouping, power(2, s_p3 )), 0, chr(0), p3 ) -- p3 , decode(bitand(l_ash_grouping, power(2, s_row_wait_obj# )), 0, chr(0), row_wait_obj# ) -- row_wait_obj# , decode(bitand(l_ash_grouping, power(2, s_row_wait_file# )), 0, chr(0), row_wait_file# ) -- row_wait_file# , decode(bitand(l_ash_grouping, power(2, s_row_wait_block# )), 0, chr(0), row_wait_block# ) -- row_wait_block# , decode(bitand(l_ash_grouping, power(2, s_row_wait_row#

)), 0, chr(0), row_wait_row#

) -- row_wait_row#

, decode(bitand(l_ash_grouping, power(2, s_blocking_session_status )), 0, chr(0), blocking_session_status ) -- blocking_session_status , decode(bitand(l_ash_grouping, power(2, s_blocking_instance )), 0, chr(0), blocking_instance ) -- blocking_instance , decode(bitand(l_ash_grouping, power(2, s_blocking_session )), 0, chr(0), blocking_session ) -- blocking_session , decode(bitand(l_ash_grouping, power(2, s_sql_hash_value )), 0, chr(0), sql_hash_value ) -- sql_hash_value , decode(bitand(l_ash_grouping, power(2, s_sql_id )), 0, chr(0), sql_id ) -- sql_id , decode(bitand(l_ash_grouping, power(2, s_sql_child_number )), 0, chr(0), sql_child_number ) -- sql_child_number , decode(bitand(l_ash_grouping, power(2, s_plsql_entry_object_id )), 0, chr(0), plsql_entry_object_id ) -- plsql_entry_object_id d d , decode(bitand(l_ash_grouping, power(2, s_plsql_entry_subprogram_i )), 0, chr(0), plsql_entry_subprogram_id ) -- plsql_entry_subprogram_i , decode(bitand(l_ash_grouping, power(2, s_plsql_object_id )), 0, chr(0), plsql_object_id ) -- plsql_object_id , decode(bitand(l_ash_grouping, power(2, s_plsql_subprogram_id )), 0, chr(0), plsql_subprogram_id ) -- plsql_subprogram_id , decode(bitand(l_ash_grouping, power(2, s_module )), 0, chr(0), module ) -- module , decode(bitand(l_ash_grouping, power(2, s_action )), 0, chr(0), action ) -- action , decode(bitand(l_ash_grouping, power(2, s_client_identifier )), 0, chr(0), client_identifier ) -- client_identifier , decode(bitand(l_ash_grouping, power(2, s_service_name )), 0, chr(0), service_name ) -- service_name order by count(*)/g_ash_samples_taken desc ) where rownum <= p_topn ) loop l_output_line := ''; o_sid = chr(0) THEN null o_username = chr(0) THEN null o_machine = chr(0) THEN null o_terminal = chr(0) THEN null := CASE WHEN i.sid ELSE nvl(i.sid := CASE WHEN i.username ELSE nvl(i.username := CASE WHEN i.machine ELSE nvl(i.machine := CASE WHEN i.terminal ELSE nvl(i.terminal , ' ') END; , ' ') END; , ' ') END; , ' ') END;

o_program := CASE WHEN i.program = chr(0) THEN null ELSE nvl(i.program , ' ') END; o_event := CASE WHEN i.event = chr(0) THEN null ELSE nvl(i.event , ' ') END; o_wait_class := CASE WHEN i.wait_class = chr(0) THEN null ELSE nvl(i.wait_class , ' ') END; o_state := CASE WHEN i.state = chr(0) THEN null ELSE nvl(i.state , ' ') END; o_p1 := CASE WHEN i.p1 = chr(0) THEN null ELSE nvl(i.p1 , ' ') END; o_p2 := CASE WHEN i.p2 = chr(0) THEN null ELSE nvl(i.p2 , ' ') END; o_p3 := CASE WHEN i.p3 = chr(0) THEN null ELSE nvl(i.p3 , ' ') END; o_row_wait_obj# := CASE WHEN i.row_wait_obj# = chr(0) THEN null ELSE nvl(i.row_wait_obj# , ' ') END; o_row_wait_file# := CASE WHEN i.row_wait_file# = chr(0) THEN null ELSE nvl(i.row_wait_file# , ' ') END; o_row_wait_block# := CASE WHEN i.row_wait_block# = chr(0) THEN null ELSE nvl(i.row_wait_block# , ' ') END; o_row_wait_row# := CASE WHEN i.row_wait_row# = chr(0) THEN null ELSE nvl(i.row_wait_row# , ' ') END; o_blocking_session_status := CASE WHEN i.blocking_session_status = chr(0) THEN null ELSE nvl(i.blocking_session_status , ' ') END; o_blocking_instance := CASE WHEN i.blocking_instance = chr(0) THEN null ELSE nvl(i.blocking_instance , ' ') END; o_blocking_session := CASE WHEN i.blocking_session = chr(0) THEN null ELSE nvl(i.blocking_session , ' ') END; o_sql_hash_value := CASE WHEN i.sql_hash_value = chr(0) THEN null ELSE nvl(i.sql_hash_value , ' ') END; o_sql_id := CASE WHEN i.sql_id = chr(0) THEN null ELSE nvl(i.sql_id , ' ') END; o_sql_child_number := CASE WHEN i.sql_child_number = chr(0) THEN null ELSE nvl(i.sql_child_number , ' ') END; o_plsql_entry_object_id := CASE WHEN i.plsql_entry_object_id = chr(0) THEN null ELSE nvl(i.plsql_entry_object_id , ' ') END; o_plsql_entry_subprogram_id := CASE WHEN i.plsql_entry_subprogram_id = chr(0) THEN null ELSE nvl(i.plsql_entry_subprogram_id , ' ') END; o_plsql_object_id := CASE WHEN i.plsql_object_id = chr(0) THEN null ELSE nvl(i.plsql_object_id , ' ') END; o_plsql_subprogram_id := CASE WHEN i.plsql_subprogram_id = chr(0) THEN null ELSE nvl(i.plsql_subprogram_id , ' ') END; o_module := CASE WHEN i.module = chr(0) THEN null ELSE nvl(i.module , ' ') END; o_action := CASE WHEN i.action = chr(0) THEN null ELSE nvl(i.action , ' ') END; o_client_identifier := CASE WHEN i.client_identifier = chr(0) THEN null ELSE nvl(i.client_identifier , ' ') END; o_service_name := CASE WHEN i.service_name = chr(0) THEN null ELSE nvl(i.service_name , ' ') END; -- print the activity % as the first column l_output_line := lpad(to_char(round(i.average_active_samples*100))||'% ', w_activity_pct, ' '); -- loop through ash columns to find what to print and in which order for s in ( -- ORA9 SQL*Plus returns only a single row with CONNECT BY LEVEL; An additonal o uter SELECT * from (...) fixes this

&_IF_ORA9

select * from ( SELECT LEVEL , SUBSTR ( TOKEN , DECODE(LEVEL, 1, 1, INSTR(TOKEN, DELIMITER, 1, LEVEL-1 , INSTR(TOKEN, DELIMITER, 1, LEVEL) DECODE(LEVEL, 1, 1, INSTR(TOKEN, DELIMITER, 1, LEVEL-1)+1

)+1) ) ) TOKEN FROM ( SELECT REPLACE( LOWER(p_ash_columns) ,' ','')||'+' AS TOK EN , '+' FROM DUAL AS DELIMITER ) CONNECT BY INSTR(TOKEN, DELIMITER, 1, LEVEL)>0 &_IF_ORA9 ) ORDER BY LEVEL ASC ) loop l_output_line := l_output_line || ' | ' || case s.token -- actual column names in v$session when 'sid' , w_sid , ' ') when 'username' , w_username , ' ') when 'machine' , w_machine , ' ') when 'terminal' , w_terminal , ' ') when 'program' , w_program , ' ') when 'event' , w_event , ' ') when 'wait_class' , w_wait_class , ' ') when 'state' , w_state , ' ') when 'p1' , w_p1 , ' ') when 'p2' , w_p2 , ' ') when 'p3' , w_p3 , ' ') when 'row_wait_obj#' bj# , w_row_wait_obj# , ' ') when 'row_wait_file#' ile# , w_row_wait_file# , ' ') when 'row_wait_block#' lock# , w_row_wait_block# , ' ') when 'row_wait_row#' ow# , w_row_wait_row# , ' ') when 'blocking_session_status' ession_status , w_blocking_session_status , ' ') when 'blocking_instance' nstance , w_blocking_instance , ' ') when 'blocking_session' ession , w_blocking_session , ' ')

then lpad(o_sid then rpad(o_username then rpad(o_machine then rpad(o_terminal then rpad(o_program then rpad(o_event then rpad(o_wait_class then rpad(o_state then rpad(o_p1 then rpad(o_p2 then rpad(o_p3 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

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

me

when 'service' , w_service_name when 'wait_event' , w_event when 'wait_state' , w_state else '' end; -- case s.token

then rpad(o_service_na , ' ') then rpad(o_event , ' ') then rpad(o_state , ' ')

end loop; -- ash parameter tokenizer output(l_output_line); end loop; -- grouped ash samples end out_ash; -- and it begins!!! begin -- get snappers own sid into g_mysid select sid into g_mysid from v$mystat where rownum = 1; pagesize := nvl( getopt('&snapper_options', 'pagesize=' ), pagesize); --output ( 'Pagesize='||pagesize ); lv_ash := getopt('&snapper_options', 'ash'); lv_stats := getopt('&snapper_options', 'stat'); if lv_ash is not null then gather_ash := 1; end if; if lv_stats is not null then gather_stats := 1; end if; --output('all='||case when getopt('&snapper_options', 'all') = chr(0) then ' chr(0)' when getopt('&snapper_options', 'all') is null then 'null' else (getopt( '&snapper_options','all')) end); -- some additional default value logic if getopt('&snapper_options', 'all') is not null then --output('setting stats to all due to option = all'); gather_stats := 1; gather_ash := 1; else if (lv_ash is null and lv_stats is null) then gather_stats := 0; gather_ash := 1; end if; end if; -- determine which performance counters and stats to collect lv_gather := case nvl( lower(getopt ('&snapper_options', 'gather=')), 'stw') when 'all' then 'stw' else nvl( lower(getopt ('&snapper_options', 'gather=')), 'st w') end; --lv_gather:=getopt ('&snapper_options', 'gather='); --output('lv_gather='||lv_gather);

if pagesize > 0 then output(' '); output('-- Session Snapper v3.63 by Tanel Poder ( http://blog.tanelpoder .com )'); output(' '); end if; -- initialize statistic and event name array -- fetch statistic names with their adjusted IDs select * bulk collect into sn_tmp from ( select 'STAT' stype, statistic# - pls_adjust st atistic#, name from v$statname where (lv_gather like '%s%' or lv_gather like ' %a%') -union all select 'WAIT', event# + (select count(*) from v$statnam e) + 1 - pls_adjust, name from v$event_name where (lv_gather like '%w%' or lv_gather like ' %a%') -&_IF_ORA10_OR_HIGHER union all &_IF_ORA10_OR_HIGHER select 'TIME' stype, stat_id - pls_adjust stati stic#, stat_name name &_IF_ORA10_OR_HIGHER from v$sys_time_model &_IF_ORA10_OR_HIGHER where (lv_gather like '%t%' or lv_gather like ' %a%') -union all select 'LATG', l.latch# + (select count(*) from v$statname) + (select count(*) from v$event_name) + 1 - pls_adjust statistic#, name from v$latch l where (lv_gather like '%l%' or lv_gather like ' %a%') -&_IF_X_ACCESSIBLE union all &_IF_X_ACCESSIBLE select 'BUFG', &_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 v$latch) + &_IF_X_ACCESSIBLE 1 - 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', ascii(substr(e.eq_type,1,1))*256 + ascii(

substr(e.eq_type,2,1)) + (select count(*) from v$statname) + (select count(*) from v$event_name) + (select count(*) from v$latch) + (select count(*) from x$kcbwh) + 1 - pls_adjust statistic#, eq_type from ( &_IF_ORA10_OR_HIGHER select es.eq_type ||' - '||lt.name eq_type, total_req# from v$enqueue_stat es , v$lock_type lt where es.eq_type = lt.type ) e where (lv_gather like '%e%' or lv_gather like ' %a%') ) snapper_statnames order by stype, statistic#; -- store these into an index_by array organized by statistic# for fast looku p --output('sn_tmp.count='||sn_tmp.count); --output('lv_gather='||lv_gather); for i in 1..sn_tmp.count loop -- output('i='||i||' statistic#='||sn_tmp(i).statistic#); sn(sn_tmp(i).statistic#) := sn_tmp(i); end loop; -- main sampling loop for c in 1..&snapper_count loop -- sesstat and other performance counter sampling if gather_stats = 1 then -- print header if required gv_header_string := CASE WHEN output_header END || CASE WHEN output_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 ,' ')||',' END || CASE WHEN output_delta END || CASE WHEN output_delta_s END || CASE WHEN output_hdelta END

&_IF_X_ACCESSIBLE

&_IF_ORA10_OR_HIGHER &_IF_ORA10_OR_HIGHER

= 1 THEN 'HEAD,' = 1 THEN ' SID,'

= 1 THEN ' USERNAME ,' = 1 THEN ' SNAPSHOT START = 1 THEN ' SECONDS,' = 1 THEN ' TYPE,' = 1 THEN rpad(' STATISTIC',59 = 1 THEN ' DELTA,' ,

= 1 THEN ' DELTA/SEC,' = 1 THEN ' HDELTA,'

|| CASE WHEN output_hdelta_s END || CASE WHEN output_percent END || CASE WHEN output_pcthist END || CASE WHEN output_eventcnt END END || CASE WHEN output_eventavg END ;

= 1 THEN ' HDELTA/SEC,' = 1 THEN ' %TIME,' ,'

= 1 THEN ' GRAPH = 1 THEN ' NUM_WAITS,'

|| CASE WHEN output_eventcnt_s = 1 THEN ' WAITS/SEC,' = 1 THEN ' AVERAGES'

if pagesize > 0 and mod(c-1, pagesize) = 0 then output(rpad('-',length(gv_header_string),'-')); output(gv_header_string); output(rpad('-',length(gv_header_string),'-')); else if pagesize = -1 and c = 1 then output(gv_header_string); end if; end if; if c = 1 then get_sessions; snap(d1,s1); else get_sessions; d1 := d2; s1 := s2; end if; -- c = 1 -- output('snapper_sleep='||to_char(&snapper_sleep - (sysdate - d1)* 86400)); -- dbms_lock.sleep( (&snapper_sleep - (sysdate - d1)) ); -- dbms_lock.sleep( (&snapper_sleep - (sysdate - d1))*1000/1024 ); end if; -- gather_stats = 1

-- ASH style sampling ash_date1 := sysdate; if gather_ash = 1 then while sysdate < (ash_date1 + (&snapper_sleep/86400)) loop -- get active session records from g_sessions get_sessions; extract_ash(); -- sleep timeout backoff depending on the duration sampled (for u p to 10 seconds total sampling time will get max 100 Hz sampling)

-- for longer duration sampling the algorithm will back off and f or long durations (over 100 sec) the sampling rate will stabilize -- at 1Hz dbms_lock.sleep( greatest(0.1,(least(1,&snapper_sleep*&snapper_co unt/100))) ); end loop; else dbms_lock.sleep( ((ash_date1+(&snapper_sleep/86400)) - sysdate)*8640 0 ); end if; ash_date2 := sysdate; -- sesstat new sample and delta calculation if gather_stats = 1 then get_sessions; snap(d2,s2); -- manually coded nested loop outer join for calculating deltas: -- why not use a SQL join? this would require creation of PL/SQL -- collection object types, but Snapper does not require any changes -- to the database, so any custom object types are out! changed_values := 0; missing_values_s1 := 0; missing_values_s2 := 0; -- remember last disappeared SID so we wouldn't need to output a war ning -- message for each statistic row of that disappeared sid disappeared_sid := 0; i :=1; -- iteration counter (for debugging) a :=1; -- s1 array index b :=1; -- s2 array index if s2.count > 0 then lv_curr_sid := s2(a).sid; end if; while ( a <= s1.count and b <= s2.count ) loop if lv_curr_sid != 0 and lv_curr_sid != s2(a).sid then if pagesize > 0 and mod(c-1, pagesize) = 0 then output(' '); output(rpad('-',length(gv_header_string),'-')); output(gv_header_string); output(rpad('-',length(gv_header_string),'-')); else output(' '); end if; lv_curr_sid := s2(a).sid; end if; delta := 0; -- don't print case when s1(a).sid = s2(b).sid then case

when s1(a).statistic# = s2(b).statistic# then delta := s2(b).value - s1(a).value; evcnt := s2(b).event_count - s1(a).event_count; if delta != 0 then fout(); end if; a := a + 1; b := b + 1; when s1(a).statistic# > s2(b).statistic# then delta := s2(b).value; evcnt := s2(b).event_count; if delta != 0 then fout(); end if; b := b + 1; when s1(a).statistic# < s2(b).statistic# then output('ERROR, s1(a).statistic# < s2(b).statisti c#, a='||to_char(a)||' b='||to_char(b)||' s1.count='||s1.count||' s2.count='||s2 .count||' s2.count='||s2.count); a := a + 1; b := b + 1; else output('ERROR, s1(a).statistic# ? s2(b).statisti c#, a='||to_char(a)||' b='||to_char(b)||' s1.count='||s1.count||' s2.count='||s2 .count||' s2.count='||s2.count); a := a + 1; b := b + 1; end case; -- s1(a).statistic# ... s2(b).statistic# when s1(a).sid > s2(b).sid then delta := s2(b).value; evcnt := s2(b).event_count; if delta != 0 then fout(); end if; b := b + 1; when s1(a).sid < s2(b).sid then if disappeared_sid != s2(b).sid then output('WARN, Session has disappeared during snapsho t, ignoring SID='||to_char(s2(b).sid)||' debug(a='||to_char(a)||' b='||to_char(b )||' s1.count='||s1.count||' s2.count='||s2.count||' s2.count='||s2.count||')'); end if; disappeared_sid := s2(b).sid; a := a + 1; else output('ERROR, Should not be here, SID='||to_char(s2(b). sid)||' a='||to_char(a)||' b='||to_char(b)||' s1.count='||s1.count||' s2.count=' ||s2.count||' s2.count='||s2.count); end case; -- s1(a).sid ... s2(b).sid i:=i+1;

if delta != 0 then changed_values := changed_values + 1; end if; -- delta != 0 end loop; -- while ( a <= s1.count and b <= s2.count ) if pagesize > 0 and changed_values > 0 then output(' '); --output('-- End of Stats snap '||to_char(c)||', end='||to_char (d2, 'YYYY-MM-DD HH24:MI:SS')||', seconds='||to_char(case (d2-d1) when 0 then &s napper_sleep else round((d2-d1) * 86400, 1) end)); output('-- End of Stats snap '||to_char(c)||', end='||to_char(d 2, 'YYYY-MM-DD HH24:MI:SS')||', seconds='||to_char(round((d2-d1) * 86400, 1))); end if; output(' '); end if; -- gather_stats = 1 if gather_ash = 1 then -- get ASH sample grouping details g_ash_columns := nvl( getopt('&snapper_options', 'ash=' ), g_ash_c olumns ); -- optional additional ASH groupings g_ash_columns1 := case when getopt('&snapper_options', 'ash1' ) is n null when getopt('&snapper_options', 'ash1' ) = chr(0) then g_ash_colum getopt('&snapper_options', 'ash1=' ) end; g_ash_columns2 := case when getopt('&snapper_options', 'ash2' ) is n null when getopt('&snapper_options', 'ash2' ) = chr(0) then g_ash_colum getopt('&snapper_options', 'ash2=' ) end; g_ash_columns3 := case when getopt('&snapper_options', 'ash3' ) is n null when getopt('&snapper_options', 'ash3' ) = chr(0) then g_ash_colum getopt('&snapper_options', 'ash3=' ) end; -- group ASH records and print report out_ash( g_ash_columns, 10 ); -- group and print optional ASH reports if g_ash_columns1 is not null then out_ash( g_ash_columns1, 10 ); en d if; if g_ash_columns2 is not null then out_ash( g_ash_columns2, 10 ); en d if; if g_ash_columns3 is not null then out_ash( g_ash_columns3, 10 ); en d if; if pagesize > 0 then output(' '); output('-- End of ASH snap '||to_char(c)||', end='||to_char(ash _date2, 'YYYY-MM-DD HH24:MI:SS')||', seconds='||to_char(round((ash_date2-ash_dat e1) * 86400, 1))||', samples_taken='||g_ash_samples_taken); --output('-- End of ASH snap '||to_char(c)||', end='||to_char(a sh_date2, 'YYYY-MM-DD HH24:MI:SS')||', seconds='||to_char(case (ash_date2-ash_da te1) when 0 then &snapper_sleep else round((ash_date2-ash_date1) * 86400, 1) end )||', samples_taken='||g_ash_samples_taken); output(' ');

ull then ns1 else ull then ns2 else ull then ns3 else

end if; reset_ash(); end if; -- gather_ash = 1 end loop; -- for c in 1..snapper_count end; / undefine snapper_oraversion undefine snapper_sleep undefine snapper_count undefine snapper_sid undefine ssid_begin -- undefine _IF_ORA10_OR_HIGHER -- undefine _IF_ORA9 -- 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 col snapper_ora10higher clear col snapper_ora11higher clear col snapper_ora11lower clear col dbms_system_accessible clear set serveroutput off

S-ar putea să vă placă și