Module: REGTEST.SQL Action: CREATE Client Info: Stats: elapsed secs: 15.93, physical reads: 137, logical reads: 8407 PL/SQL procedure successfully completed.. 7.3.6 Covering DBMS_APP
Trang 1
IF display_TF AND
(current_module IS NOT NULL OR current_client_info IS NOT NULL)
THEN
END set_stats;
7.3.5 Using the register_app Package
The following SQL*Plus script demonstrates how the register_app package can be used to register each step
of a multistep batch process The script displays the resource utilization statistics that have been collected for each step While the script is executing, DBAs can monitor which step is currently running by querying V$SESSION for the session executing the script
/* Filename on companion disk: regtest.sql */*
rem ======================================================
rem REGTEST.SQL
rem
rem SQL*Plus script to demonstrate the use of package
rem REGISTER_APP for tracking performance statistics
rem
rem ======================================================
set serveroutput on size 100000
set feedback off
rem ======================================================
rem register module first with display OFF to
rem initialize stats, then set display ON
rem ======================================================
execute register_app.set_display_TF(FALSE);
execute register_app.module('REGTEST.SQL');
execute register_app.set_display_TF(TRUE);
set feedback on
rem ======================================================
rem create a table my_dictionary copied from dictionary
rem ======================================================
execute register_app.action('CREATE');
CREATE TABLE my_dictionary
(id, table_name, comments)
TABLESPACE user_data2
AS
SELECT rownum,A.*
FROM dictionary A;
rem ======================================================
rem update one third of my_dictionary rows
rem ======================================================
execute register_app.action('UPDATE');
UPDATE my_dictionary
SET comments = RPAD(comments,2000,'*')
WHERE MOD(id,3) = 0;
rem ======================================================
rem delete one third of my_dictionary rows
rem ======================================================
execute register_app.action('DELETE');
DELETE FROM my_dictionary
WHERE MOD(id,3) = 1;
Trang 2rem ======================================================
rem drop table my_dictionary
rem ======================================================
execute register_app.action('DROP');
DROP TABLE my_dictionary;
rem ======================================================
rem unregister and display previous step stats
rem ======================================================
execute register_app.module(null,null);
Here is sample output generated by the script:
SQL> @regtest
Module: REGTEST.SQL
Action: BEGIN
Client Info:
Stats: elapsed secs: 15, physical reads: 0, logical reads: 0
PL/SQL procedure successfully completed Table created Module: REGTEST.SQL
Action: CREATE
Client Info:
Stats: elapsed secs: 15.93, physical reads: 137, logical reads: 8407
PL/SQL procedure successfully completed 92 rows updated Module: REGTEST.SQL
Action: UPDATE
Client Info:
Stats: elapsed secs: 9.32, physical reads: 8, logical reads: 2075
PL/SQL procedure successfully completed 93 rows deleted Module: REGTEST.SQL
Action: DELETE
Client Info:
Stats: elapsed secs: 6, physical reads: 0, logical reads: 296
PL/SQL procedure successfully completed Table dropped Module: REGTEST.SQL
Action: DROP
Client Info:
Stats: elapsed secs: 5.36, physical reads: 35, logical reads: 356 PL/SQL procedure successfully completed.
7.3.6 Covering DBMS_APPLICATION_INFO
Oracle suggests in the DBMS_APPLICATION_INFO package documentation that DBAs may want to
develop a cover package called DBMS_APPLICATION_INFO in a schema other than SYS By redirecting
the public synonym DBMS_APPLICATION_INFO to point at this version of the package, any programs
Trang 3referencing DBMS_APPLICATION_INFO programs will use the new package Any functional extensions to DBMS_APPLICATION_INFO in the cover package will be immediately picked up by programs using DBMS_APPLICATION_INFO In this way, resource tracking like that demonstrated by the register_app package can be implemented globally for programs using DBMS_APPLICATION_INFO
Instead of directly covering DBMS_APPLICATION_INFO with a package of the same name, I chose to create the register_app package One reason for this: I prefer the shorter and more meaningful name
register_app New applications can call register_app directly and avoid the painfully long
DBMS_APPLICATION_INFO package name Another reason was that I wanted to extend the functionality
of DBMS_APPLICATION_INFO with new programs, and thus the new package would not look identical to DBMS_APPLICATION_INFO When covering an Oracle built−in package, it is good practice to create a package with an identical specification (or API) to that of the built−in
We can actually cover DBMS_APPLICATION_INFO with a package that calls the register_app programs In this way, the functionality of register_app is extended to programs that reference
DBMS_APPLICATION_INFO directly, and we still have our new package to use for new programs
The following code shows how DBMS_APPLICATION_INFO.SET_MODULE can be covered in this way:
CREATE OR REPLACE PACKAGE BODY DBMS_APPLICATION_INFO
IS
PROCEDURE set_module
(module_name IN VARCHAR2
,action_name IN VARCHAR2)
IS
register_app.module(module_name, action_name);
END set_module;
Notice that the SET_MODULE cover procedure is identical in signature to the program of the same name in the SYS version of the DBMS_APPLICATION_INFO package
Q: Why must the cover package for DBMS_APPLICATION_INFO match all program signatures identically,
including parameter names?
A: The program signatures in the cover package to DBMS_APPLICATION_INFO must match those in the
SYS version of the package because existing calls to DBMS_APPLICATION_INFO could otherwise be compromised It is necessary to match not only the number of parameters and their datatypes and modes (IN
or OUT) but also the parameter names The parameter names must match in order to preserve functionality in existing programs calling DBMS_APPLICATION_INFO using named notation The following fragment illustrates code that will not work if the cover package does not preserve parameter names in the signature for the SET_MODULE procedure:
DECLARE
module_var VARCHAR2(64) := 'Program 1';
action_var VARCHAR2(64) := 'Transaction A';
BEGIN
DBMS_APPLICATION_INFO.SET_MODULE
(module_name=>module_var
,action=>action_var);
END;
Q: What necessary precaution was taken in the register_app package to ensure that it could be used as part
of a cover package for DBMS_APPLICATION_INFO?
A: All calls to DBMS_APPLICATION_INFO in the register_app package are fully qualified with the schema
name (SYS) This way, when the public synonym DBMS_APPLICATION_INFO is redirected to point at the cover package, an infinite loop is avoided and the SYS version of the package is ultimately called
Trang 4Exercise for the reader: Create the full cover package for DBMS_APPLICATION_INFO using the
register_app package
7.3.7 Monitoring Application SQL Resource Consumption
When applications make use of DBMS_APPLICATION_INFO to register themselves, DBAs can monitor application usage and resource consumption through the V$SESSION and V$SQLAREA virtual tables The following is a simple report summarizing SQL resource consumption data by application module and action Such reports can serve a number of useful purposes, including the following:
•
Identifying tuning opportunities
•
Quantifying utilization levels by application component
•
Implementing chargeback schemes
/* Filename on companion disk: sqlarea.sql */
rem ======================================================
rem SQLAREA.SQL
rem Simple report from V$SQLAREA on SQL resource
rem utilization by module and action
rem ======================================================
col module format a15
col action format a15
SELECT module
,action
,SUM(buffer_gets) buffer_gets
,SUM(rows_processed) rows_processed
,SUM(disk_reads) disk_reads
FROM sys.v_$sqlarea
WHERE module IS NOT NULL
AND action IS NOT NULL
GROUP BY module, action;
The following output was generated by the script after regtest.sql had been executed several times:
SQL> @sqlarea
MODULE ACTION BUFFER_GETS ROWS_PROCESSED DISK_READS
−−−−−−−−−−−−− −−−−−−−−−−−−−−− −−−−−−−−−−− −−−−−−−−−−−−−− −−−−−−−−−−
REGTEST.SQL BEGIN 0 7 0
REGTEST.SQL CREATE 0 7 0
REGTEST.SQL DELETE 1014 313 0
REGTEST.SQL DROP 0 7 0
REGTEST.SQL UPDATE 6721 308 33
5 rows selected.
7.3.8 Session Monitoring and Three−Tier Architectures
While writing this section on DBMS_APPLICATION_INFO, I had occasion to recommend the use of this package to help solve two real−world issues that came to my attention In one case, an application had been written to call DBMS_SESSION.SET_SQL_TRACE and thus turn SQL tracing on for a session running the application.[1] The DBA wanted to know which sessions were being traced at any given time I suggested the
Trang 5use of DBMS_APPLICATION_INFO.SET_CLIENT_INFO to put a message into the V$SESSION table indicating a tracing session The procedure to set tracing could look something like this:
[1] Coding applications with the ability to set SQL tracing on and off is very good practice, as
it can greatly assist in the detection of post−deployment runtime performance problems
PROCEDURE set_trace (on_TF IN BOOLEAN)
IS
BEGIN
IF on_TF
THEN
DBMS_APPLICATION_INFO.SET_CLIENT_INFO('TRACE ON');
ELSE
DBMS_APPLICATION_INFO.SET_CLIENT_INFO('');
END IF;
DBMS_SESSION.SET_SQL_TRACE(on_TF);
END set_trace;
In the second example, I was discussing with another DBA the difficult issue of tracking down specific users
in the following types of applications:
•
Three−tier applications like Oracle WebServer where users do not connect to Oracle directly, but through proxy connections held by the application server
•
Applications where all users connect to Oracle under a common username, and security and
user−differentiation are maintained entirely within the application at runtime
Both of these architectures make it difficult for the DBA to correlate specific end users with the database sessions they are currently using In the first case, sessions are persistent and serve different users at different times −− and sometimes no user at all In the second case, all user sessions connect to a common username and thus are indistinguishable (by username) in V$SESSION Interestingly enough, these are both perfect opportunities to use DBMS_APPLICATION_INFO.SET_CLIENT_INFO When users connect to the
application, call a procedure like the set_user procedure in the example for
DBMS_APPLICATION_INFO.SET_CLIENT_INFO A better version of set_user would call
register_app.client_info to enable performance statistics tracking for the application users
7.3.9 Tracking Long−Running Processes
The SET_SESSION_LONGOPS procedure is an interesting addition to DBMS_APPLICATION_INFO first found in the Oracle8 version of the package Oracle documentation makes it clear that the intended use of the procedure is to enable external tracking of the progress of long−duration operations through the new virtual table, V$SESSION_LONGOPS However, I found SET_SESSION_LONGOPS rather nonintuitive and unwieldy to use
One difficult concept is the reuse of the four rows in V$SESSION_LONGOPS based on unique combinations
of context and stepid, and how this relates to the hint parameter, which is used to identify the row to modify Context and stepid do not have to be unique among the rows in V$SESSION_LONGOPS, but setting a new context/stepid combination will always cause acquisition of a new row Because multiple rows can be
identical in context/stepid, they do not really form a key (along with the session SID) to the virtual table The hint parameter to DBMS_APPLICATION_INFO.SET_SESSION_LONGOPS seems to be the only way to identify which row is currently being set, but there is no column in V$SESSION_LONGOPS corresponding
to the hint Thus it is actually impossible to externally identify with accuracy the row modified by the last call
to the procedure This defeated my efforts to write a READ_SESSION_LONGOPS procedure that takes a hint value in and reports the values for the row identified by that hint value