In my previous post, we saw how to trace individual sessions. The challenge involved in real world performance issues is that mostly there won't be any single session that would run in the DB but the application would spawn multiple processes/sessions. So in this case if we want to trace a session, it will be tedious task to identify which session to trace. Many time there would be run away sessions and a few times even the developers wouldn't be knowing the entire work flow which will again add complexity to the existing issue.
During these times, instead of tracing individual session we can go ahead and trace set of sessions using application tracing methods. In this post, we will look at the methods on how to do the application tracing
Application level tracing
Application tracing can be performed by using
- DBMS_SQL_MONITOR
- DBMS_MONITOR
We will have a separate post on DBMS_SQL_MONITOR later and now will look into the usage of DBMS_MONITOR
DBMS_MONITOR
Information that we need to proceed with application tracing using dbms_monitor are either of the 3 below
- Client info
- Module
- Action
SQL> set sqlformat ansiconsole SQL> select sid, serial#, username, client_info, module, action from v$session where username not in ('SYS','SYSTEM') SID SERIAL# USERNAME CLIENT_INFO MODULE ACTION --------------------------------------------------------------------------------------------- 17 63073 SOE Swingbench Load Generator JDBC Thin Client 401 47594 SOE Swingbench Load Generator JDBC Thin Client 778 11025 SOE SQL*Plus 780 55219 SYSRAC oraagent.bin@linux75-2.selvapc.com (TNS V1-V3) 1151 4268 SOE Swingbench Load Generator JDBC Thin Client 1157 61639 SYSRAC oraagent.bin@linux75-2.selvapc.com (TNS V1-V3) 1158 10873 TEST SQL Developer 1166 11417 SOE Swingbench Load Generator JDBC Thin Client 8 rows selected. SQL>You can see a few session has CLIENT_INFO and a few doesn't and none of sessions has info on ACTION field.
CREATE OR replace PROCEDURE up_test1 AS BEGIN dbms_application_info.set_module(module_name=> 'Change name', action_name=> 'insert id'); INSERT INTO test1 (id,name) VALUES (102,'ORABLISS'); dbms_application_info.set_action(action_name=> 'update id'); UPDATE test1 SET id = 101 WHERE name = 'test'; dbms_application_info.set_module(NULL, NULL); END; /You can see I have inserted DBMS_APPLICATION_INFO.SET_MODULE in 2 places one with module_name and action_name and another with only action_name. This way we can trace the parts only we need in code with large number of lines.
SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_ENABLE(service_name=>'ORCL',module_name=>'Change name'); PL/SQL procedure successfully completed. -- Run the procedure using other session which will trigger the tracing -- Once the procedure is completed we can disable trace as follows. SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_disable(service_name=>'ORCL',module_name=>'Change name'); PL/SQL procedure successfully completed. SQL>
For tracing sessions performing specific action:
SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_ENABLE(service_name=>'ORCL',module_name=>'Change name',action_name=> 'update id',waits=>true,binds=>true); PL/SQL procedure successfully completed. -- Run the procedure using other session which will trigger the tracing -- This time tracing will capture only the update statement in the procedure as the action is named as 'update id' -- Once the procedure is completed we can disable trace as follows. SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_disable(service_name=>'ORCL',module_name=>'Change name',action_name=> 'update id'); PL/SQL procedure successfully completed. SQL>The above SERV_MOD_ACT_TRACE_ENABLE procedure follows strict hierarchy, meaning - service_name is mandatory followed by module_name and action_name. If no module_name is provided, we can't provide action_name and if no action_anme is provided all the action under the module will be traced.
SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_ENABLE(service_name=>'ORCL'); PL/SQL procedure successfully completed. -- This time tracing will capture all the sessions that connect to DB using ORCL service -- We can disable trace as follows. SQL> exec dbms_monitor.SERV_MOD_ACT_TRACE_DISABLE(service_name=>'ORCL'); PL/SQL procedure successfully completed. SQL>
v$session will have client_info filed populated for most of the application. If it is null like the example I gave in this post, we can use the DBMS_APPLICATION_INFO.SET_CLIENT_INFO procedure to set in the program/main procedure similar to below
CREATE OR replace PROCEDURE up_test2 AS BEGIN dbms_application_info.set_client_info('client info test'); dbms_session.set_identifier('client info test'); INSERT INTO test1 (id,name) VALUES (102,'ORABLISS'); UPDATE test1 SET id = 101 WHERE name = 'test'; dbms_session.clear_identifier; END; /As I have now included the DBMS_SESSION.SET_IDENTIFIER, we can trace the session without searching for the session id.
SQL> exec DBMS_MONITOR.CLIENT_ID_TRACE_ENABLE('client info test'); PL/SQL procedure successfully completed. -- Run the procedure up_test2 using other session which will trigger the tracing using client identifier -- Once the procedure is completed we can disable trace as follows (optional) SQL> exec DBMS_MONITOR.CLIENT_ID_TRACE_disable('client info test'); PL/SQL procedure successfully completed. SQL>
SQL> exec DBMS_MONITOR.DATABASE_TRACE_ENABLE; PL/SQL procedure successfully completed. -- All the sessions in the database will be traced -- waits, binds, instance_name and plan_stat can be provided as arguments -- To disable tracing SQL> exec DBMS_MONITOR.DATABASE_TRACE_DISABLE; PL/SQL procedure successfully completed. SQL>
Hi Selva.. this is really interesting.
ReplyDeleteJust a clarification. If a main package where we set client info calls another underlying procedure or function inside, still the tracing track them ?
Hi Amuthan,
DeleteYes, it should trace the the function and procedure that comes under the main package. You can try creating another procedure as below
create or replace procedure up_test3 as
BEGIN
INSERT INTO test1 (id,name)
VALUES (102,'ORABLISS');
UPDATE test1
SET id = 101
WHERE name = 'test';
END;
/
Call this proc via another proc by adding client identifier and enable trace. You will find the sql executed captured in trace file.
CREATE
OR replace PROCEDURE up_test2 AS
BEGIN
dbms_application_info.set_client_info('client info test');
dbms_session.set_identifier('client info test');
up_test3;
dbms_session.clear_identifier;
END;
/
Thanks!