Performance instrumentation is a little extra code that developers put into their PL/SQL applications that tells everyone—owners, users, system managers, and the software developers themselves—exactly where your software is spending your time. With it, managing performance is a snap. Good instrumentation makes it so normal people, not just specialists, can diagnose and solve performance problems quickly and permanently, often before your users even sense something is wrong. However, without good time-based performance instrumentation, managing performance becomes nightmarishly complex and expensive.
With as little as two lines of code you will be able to monitor specific tasks in your application and make one of the most difficult steps of implementing response-time based problem diagnosis (Method R) into one of the easiest. In addition, these techniques will enable you to correlate database statistics back to business tasks and help discover those tasks that are heavy resource consumers. This presentation will provide examples of how to perform the instrumentation using Oracle's built-in packages and a free open source instrumentation package called the Instrumentation Library for Oracle (ILO). Its cost on every level is free, and the significant collateral benefits that can be achieved will make code instrumentation part of your coding standards.
117. PROCEDURE get_emp_jobs_instr_flawed IS jtlist_stack jtlist_tab; lnlist_stack lnlist_tab; BEGIN DBMS_APPLICATION_INFO.set_module(module_name => 'Human Resources', action_name => 'Get Employees and Jobs'); get_emp_simple_instr; SELECT last_name, job_title BULK COLLECT INTO lnlist_stack, jtlist_stack FROM employees e, jobs j WHERE e.job_id = j.job_id; DBMS_APPLICATION_INFO.set_module(NULL, NULL); EXCEPTION WHEN OTHERS THEN DBMS_APPLICATION_INFO.set_module(NULL, NULL); DBMS_OUTPUT.PUT_LINE('get_emp_jobs_instr_flawed => ERROR'); END get_emp_jobs_instr_bad;
Collect properly scoped , un-aggregated profile data for each task while the task is exhibiting the behavior you want to record Login Triggers Unique code changes
Collect properly scoped , un-aggregated profile data for each task while the task is exhibiting the behavior you want to record Login Triggers Unique code changes
… costs you money
Your slow stuff will clog up even your fast stuff.
“ Slow. Why?” Ok …What does “slow” mean?
129.98 seconds Why?
129.98 seconds (this is R data) Why? Where is the time spent? (we need profile data)
Real-life performance instrumentation
Real-life performance instrumentation
Real-life performance instrumentation
Test 1: I delivered the presentation to my cats. I used a stop watch to keep a running time My cats were thrilled to participate My test presentation was just short of 2 hours
Emit a line-by-line execution of each step with a time stamp Available in any environment (e.g. development, production…) Always ready to be activated Easy to perform Light weight Uses built-in functionality as much as possible
Enterprise Manager V$ views
No idea of who are the clients Large amount of activity by unnamed modules and actions
Know who the client is and be able to drilldown See specific module and action that are the “Top Consumers” Able to trace right from DBConsole and Grid Control
Enterprise Manager V$ views
Enterprise Manager V$ views
Emit a line-by-line execution of each step with a time stamp Available in any environment (e.g. development, production…) Always ready to be activated Easy to perform Light weight Uses built-in functionality as much as possible
Create a simple logon trigger to set CLIENT_IDENTIFIER CREATE OR REPLACE TRIGGER client_id_logon_trg AFTER LOGON ON DATABASE DECLARE my_service SYS.V_$SESSION.SERVICE_NAME%TYPE; my_clientid SYS.V_$SESSION.CLIENT_IDENTIFIER%TYPE; my_ip_address SYS.V_$SESSION.TERMINAL%TYPE; my_os_user SYS.V_$SESSION.OSUSER%TYPE; my_audsid SYS.V_$SESSION.AUDSID%TYPE; my_program SYS.V_$SESSION.PROGRAM%TYPE; CLIENT_ID_DELIM CHAR(1) := '~'; BEGIN IF USER NOT IN ('SYS') AND USER IS NOT NULL THEN my_clientid := SYS_CONTEXT('USERENV', 'CLIENT_IDENTIFIER'); IF my_clientid IS NULL THEN my_service := SYS_CONTEXT('USERENV', 'SERVICE_NAME'); my_ip_address := NVL(SYS_CONTEXT('USERENV', 'IP_ADDRESS') ,SYS_CONTEXT('USERENV', 'TERMINAL')); my_os_user := SYS_CONTEXT('USERENV', 'OS_USER'); my_audsid := TO_NUMBER(SYS_CONTEXT('USERENV', 'SESSIONID')); SELECT PROGRAM INTO my_program FROM SYS.V_$SESSION WHERE AUDSID = my_audsid AND ROWNUM = 1; DBMS_SESSION.SET_IDENTIFIER(my_os_user || CLIENT_ID_DELIM || my_ip_address || CLIENT_ID_DELIM || my_program || CLIENT_ID_DELIM || my_service); END IF; END IF; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('client_id_logon_trg: Exception thrown'); END client_id_logon_trg;
Valid values of dest parameter are 1 = Trace file, 2 = Alert log, 3 = Both
Monitor sessions by querying v$session
Valid values of dest parameter are 1 = Trace file, 2 = Alert log, 3 = Both
Monitor sessions by querying v$session
http://sourceforge.net/projects/hotsos-ilo/
Turning on trace is usually a run-time decision ( DBMS_MONITOR ) The developer will simply include BEGIN_TASK ILO calls that will check to see if someone has requested that a trace be initiated For development testing, the developer simply calls SET_MARK_ALL_TASKS_INTERESTING (TRUE, TRUE) to express their intent to trace Calls to this method will not typically be present in production code Except perhaps via a menu option (Help > Debug > Trace)