0% found this document useful (0 votes)
9 views

Database Tools For Performance Monitoring

Uploaded by

Connor McDonald
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
9 views

Database Tools For Performance Monitoring

Uploaded by

Connor McDonald
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 61

www.

oracledba

co.uk
Debugging / Trace

The tools you’ll need


oracledba

.co.uk
Autotrace

10046 trace

Debugging

Error handling

2
oracledba
Pop quiz #1

.co.uk
SQL> select rowid from MY_TABLE;

ROWID
------------------
AAAG+dAALAAACaKAAA How do two different
tables have the same
rowid ?
SQL> select rowid from A_DIFFERENT_TABLE;

ROWID
------------------
AAAG+dAALAAACaKAAA

3
oracledba
Pop quiz #2

.co.uk
• In a table, how many bytes does a ROWID consume
– A) 0
– B) 6
– C) 8

• In an index, how many bytes does a ROWID consume


– A) 6
– B) 10
– C) 3950

4
oracledba
Tools

.co.uk
• Autotrace
• Database trace

5
oracledba
Autotrace

.co.uk
• Used in SQL Plus
– get the most recent version
– requires a little DBA setup

SQL> set autotrace on


Error ORA-942 while gathering statistics
Error enabling STATISTICS report
SQL>

6
oracledba
Autotrace example

.co.uk
SQL> set autotrace on
SQL> select inc_id, incident_ref from ims_incident
2 where off_id_officer_dealing = 1234;

INC_ID INCIDENT_REF mostly correct


---------- -----------------------------------
100001

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=19 Bytes=1615)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'IMS_INCIDENT' (Cost=2 Card=19 Bytes=1615)
2 1 INDEX (RANGE SCAN) OF 'INC_OFF1_DEAL_FK_I' (NON-UNIQUE) (Cost=1 Card=19)

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
7
0 rows processed
oracledba
Autotrace example

.co.uk
SQL> set autotrace on statistics
SQL> select inc_id, incident_ref from ims_incident
2 where off_id_officer_dealing = 1234;

INC_ID INCIDENT_REF
---------- -----------------------------------
100001

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

8
oracledba
Autotrace example

.co.uk
SQL> set autotrace traceonly statistics
SQL> select inc_id, incident_ref from ims_incident
2 where off_id_officer_dealing = 1234;

Statistics
----------------------------------------------------------
0 recursive calls
0 db block gets
2 consistent gets
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

9
oracledba
Autotrace example

.co.uk
SQL> set autotrace on traceonly explain
SQL> select inc_id, incident_ref from ims_incident
2 where off_id_officer_dealing = 1234;

(query not run)

Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=19 Bytes=1615)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'IMS_INCIDENT' (Cost=2 Card=19 Bytes=1615)
2 1 INDEX (RANGE SCAN) OF 'INC_OFF1_DEAL_FK_I' (NON-UNIQUE) (Cost=1 Card=19)

10
oracledba
What to look for

.co.uk
Execution Plan
----------------------------------------------------------
0 SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=19 Bytes=1615)
1 0 TABLE ACCESS (BY INDEX ROWID) OF 'IMS_INCIDENT' (Cost=2 Card=19 Bytes=1615)
2 1 INDEX (RANGE SCAN) OF 'INC_OFF1_DEAL_FK_I' (NON-UNIQUE) (Cost=1 Card=19)

• Does it make sense ?


• Do the cardinalities appear correct ?

11
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets SQL statements executed in order
2 consistent gets to execute your SQL statement.
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client • triggers
315 bytes received via SQL*Net from client • parsing
1 SQL*Net roundtrips to/from client
0 sorts (memory) • temporary space
0 sorts (disk) • plsql functions
0 rows processed

Should reduce after first execution.


Try to remove if possible.

• fold code into the SQL

12
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets Blocks read in "CURRENT" mode.
2 consistent gets
0 physical reads
0 redo size
Current mode get is a retrieve of a
2384 bytes sent via SQL*Net to client block as it exists right now.
315 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory) • update
0 sorts (disk) • insert
0 rows processed • delete
• full scans

13
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets
Request for consistent read of a
2 consistent gets block.
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client
May require reads to the undo
315 bytes received via SQL*Net from client (rollback) information.
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk) Probably the key one to focus on.
0 rows processed
• query tuning
• array fetching
• application processes / timings

14
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets Physical reads from the datafiles
2 consistent gets into the buffer cache.
0 physical reads
0 redo size
2384 bytes sent via SQL*Net to client • Reading from datafiles
315 bytes received via SQL*Net from client • Reading from temp segments
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

15
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets The total amount of redo generated
2 consistent gets in bytes during the execution of this
0 physical reads
0 redo size
statement.
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client • batch up DML
1 SQL*Net roundtrips to/from client
0 sorts (memory) • use SQL not PL/SQL
0 sorts (disk) • avoid overfrequent commits
0 rows processed

16
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets The total number of bytes
2 consistent gets sent/received between the client
0 physical reads
0 redo size
and the server.
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client Total number of SQL*Net
1 SQL*Net roundtrips to/from client
0 sorts (memory) messages sent to and received
0 sorts (disk) from the client.
0 rows processed

Includes roundtrips for FETCHES


from a multiple row result set.

• select columns you need


• array fetching

17
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets Sorts done in the user's session
2 consistent gets memory (sort area). Controlled via
0 physical reads
0 redo size
sort_area_size database
2384 bytes sent via SQL*Net to client parameter.
315 bytes received via SQL*Net from client
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk)
0 rows processed

18
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets Sorts that use the disk (temporary
2 consistent gets tablespace) because the sort
0 physical reads
0 redo size
exceeded the users sort area size.
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client DBA concern primarily
1 SQL*Net roundtrips to/from client
0 sorts (memory)
0 sorts (disk) Upgrade to ver 9
0 rows processed

19
oracledba
What to look for

.co.uk
Statistics
---------------------------------------------
0 recursive calls
0 db block gets Rows processed by modifications
2 consistent gets or returned from a SELECT
0 physical reads
0 redo size
statement.
2384 bytes sent via SQL*Net to client
315 bytes received via SQL*Net from client • was the result expected?
1 SQL*Net roundtrips to/from client
0 sorts (memory) • updates with subqueries
0 sorts (disk)
0 rows processed

20
oracledba
Database Trace

.co.uk
• The definitive performance measurement tool
– need access to server, OR
– need client software on PC

• Enabling trace
– alter session set sql_trace = true;
– alter session set events = ‘10046 trace name context forever, level nnn’;

– quick and easy way


• when-new-form-instance, FORMS_DDL('alter session set sql_trace = true');

– Build an external enabling facility!

21
oracledba
Database Trace for Developers

.co.uk
• Trace level
– 1 standard trace
– 4 standard + bind variable values
– 8 standard trace + wait events
– 12 standard trace + bind variable values + wait events

22
oracledba
Database trace

.co.uk
SQL> alter session set sql_trace = true;

SQL> select p.value||'/'||lower(d.instance_name) || '_ora_' ||


2 ltrim(to_char(a.spid)) || '.trc' filename
3 from v$process a, v$session b, v$instance d, v$parameter p
4 where a.addr = b.paddr
5 and b.audsid = userenv('sessionid')
6 and p.name = 'user_dump_dest';

FILENAME
--------------------------------------------------------------
/apps/oracle/admin/IMSDEV/udump/imsdev_ora_6560.trc

File is created on the database server

View VW_TRACE_FILE_NAME available in IMS1DE

23
oracledba
The raw data

.co.uk
/apps/oracle/admin/IMSDEV/udump/imsdev_ora_6669.trc
Oracle8i Enterprise Edition Release 8.1.7.4.0 - Production
With the Partitioning option
JServer Release 8.1.7.4.0 - Production
ORACLE_HOME = /apps/oracle/8.1.7.4
System name: SunOS
Node name: gomez
Release: 5.8
Version: Generic_108528-16
Machine: sun4u
Instance name: IMSDEV
Redo thread mounted by this instance: 1
Oracle process number: 17
Unix process pid: 6669, image: oracle@gomez (TNS V1-V3)

*** 2003-07-17 12:04:51.924


*** SESSION ID:(15.107) 2003-07-17 12:04:51.862
APPNAME mod='SQL*Plus' mh=3669949024 act='' ah=4029777240

24
oracledba
The raw data

.co.uk
PARSING IN CURSOR #1 len=29 dep=0 uid=156 oct=3 lid=156
tim=2762254524 hv=1415343577 ad='81e07370'
select count(*) from nominal
END OF STMT
PARSE #1:c=20,e=23,p=4,cr=533,cu=0,mis=1,r=0,dep=0,og=4,tim=2762254524
EXEC #1:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=2762254524
WAIT #1: nam='SQL*Net message to client' ela= 0 p1=1650815232 p2=1 p3=0
WAIT #1: nam='file open' ela= 0 p1=0 p2=0 p3=0
WAIT #1: nam='db file sequential read' ela= 2 p1=9 p2=5033 p3=1
WAIT #1: nam='db file scattered read' ela= 2 p1=9 p2=5034 p3=3
FETCH #1:c=0,e=4,p=4,cr=3,cu=4,mis=0,r=1,dep=0,og=4,tim=2762254528
WAIT #1: nam='SQL*Net message from client' ela= 0 p1=1650815232 p2=1 p3=0
FETCH #1:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=0,tim=2762254528
WAIT #1: nam='SQL*Net message to client' ela= 0 p1=1650815232 p2=1 p3=0

25
oracledba
The raw data

.co.uk
PARSING IN CURSOR #2 len=283 dep=1 uid=0 oct=3 lid=0
tim=2762255287 hv=955191413 ad='826270fc'
select obj#,type#,ctime,mtime,stime,status,dataobj#,flags,oid$,
spare1 from obj$ where owner#=:1 and name=:2 and namespace=:3
and(remoteowner=:4 or remoteowner is null and :4 is
null)and(linkname=:5 or linkname is null and :5 is
null)and(subname=:6 or subname is null and :6 is null)
END OF STMT
PARSE #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
EXEC #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
FETCH #2:c=0,e=0,p=0,cr=2,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
EXEC #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
FETCH #2:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=2762255287
=====================
PARSING IN CURSOR #3 len=46 dep=1 uid=0 oct=3 lid=0
tim=2762255287 hv=2918884618 ad='823c04ec'
select node,owner,name from syn$ where obj#=:1
END OF STMT
PARSE #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
EXEC #3:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
FETCH #3:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=2762255287
EXEC #2:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,tim=2762255287
FETCH #2:c=0,e=0,p=0,cr=3,cu=0,mis=0,r=1,dep=1,og=4,tim=2762255287
26
oracledba
The raw data – a closer look

.co.uk
len = length of SQL dep = recursive depth uid = user executing
oct = oracle command type
lid = access user id
tim = time snapshot
ad = sql address
PARSING IN CURSOR #1 len=29 dep=0 uid=156 oct=3 lid=156
tim=2762254524 hv=1415343577 ad='81e07370' hv = hash value

select count(*) from nominal


END OF STMT
c = cpu p = physical reads cu = current reads r = rows processed og = optimizer goal

PARSE #1:c=20,e=23,p=4,cr=533,cu=0,mis=1,r=0,dep=0,og=4,tim=2762254524

e = elapsed cr = consistent reads mis = library cache miss dep = recursive depth tim = time snapshot

EXEC #1:c=0,e=0,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4,tim=2762254524
WAIT #1: nam='db file sequential read' ela= 2 p1=9 p2=5033 p3=1
FETCH #1:c=0,e=4,p=4,cr=3,cu=4,mis=0,r=1,dep=0,og=4,tim=2762254528
27
ela = elapsed p1,p2,p3 = dependent on wait
oracledba
Cleaning it up

.co.uk
tkprof imsdev_ora_6669.trc xyz.prf sort=… sys=…

select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156

Rows Row Source Operation


------- ---------------------------------------------------
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913)
28
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156 How many times ?
Rows Row Source Operation
------- --------------------------------------- Parse to execute ratio.
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913)
All counts = 1 for all SQL
(not using bind variables)

29
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156

Rows Row Source Operation Was this query already in the


------- --------------------------------------- shared pool?
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913)

30
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156

Rows Row Source Operation What optimizer did I use?


------- ---------------------------------------
1 SORT AGGREGATE (Note: Does not tell you the
832 INDEX FAST FULL SCAN (object id 75913)
results of ‘choose’)

31
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156 SQL> select username
2 from dba_users
Rows Row Source Operation
------- --------------------------------------- 3 where user_id = 156;
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913) USERNAME
------------------------------
PD71986
32
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156
The true explain plan that was
Rows Row Source Operation
------- --------------------------------------- used.
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913) The only one you can really
trust.

33
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156
The important stuff.
Rows Row Source Operation
------- ---------------------------------------
1 SORT AGGREGATE Big CPU/Elapsed = problems
832 INDEX FAST FULL SCAN (object id 75913)
CPU vs Elapsed = waiting?

34
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156

Rows Row Source Operation


------- ---------------------------------------
Am I doing single row (bad)
1 SORT AGGREGATE fetches or array (good) fetch ?
832 INDEX FAST FULL SCAN (object id 75913)

35
oracledba
A closer look

.co.uk
select count(*)
from nominal

call count cpu elapsed disk query current rows


------- ------ -------- ---------- ---------- ---------- ---------- ----------
Parse 1 0.10 0.13 0 0 0 0
Execute 1 0.00 0.00 0 0 0 0
Fetch 2 0.00 0.04 4 3 4 1
------- ------ -------- ---------- ---------- ---------- ---------- ----------
total 4 0.10 0.17 4 3 4 1

Misses in library cache during parse: 1


Optimizer goal: CHOOSE
Parsing user id: 156
How much physical and logical
Rows Row Source Operation
------- --------------------------------------- I/O did the query do?
1 SORT AGGREGATE
832 INDEX FAST FULL SCAN (object id 75913) High numbers = problems

36
oracledba
Database Trace

.co.uk
• Options
– sort controls order of SQL output (tkprof no parameters)
– sys omit/include recursive SQL from output
– record present list of SQL’s in order executed

37
oracledba
Debugging in the database

.co.uk
• Package dbpk_debug (for database routines)
dbpk_debug.msg('Up to here in code');

Puts 'Up to here in code' in CLIENT_INFO field in V$SESSION

dbpk_debug.msg('Adding GUS_ID %s to table',100);

'Adding GUS_ID 100 to table'

dbpk_debug.msg('Users %s, %s, %s are invalid',


'USER1',
'USER2'
'USER3');
'Users USER1, USER2, USER3 are invalid'

38
oracledba
Example

.co.uk
PROCEDURE dbp_convert_nominal AS
BEGIN
dbpk_debug.msg('Start');
IF pc_sex_code IS NULL THEN
lc_sex_code := dbpk_common.dbf_string('SEX NOT KNOWN');
lc_sex_desc := NULL;
ELSE
lc_sex_code := pc_sex_code;
lc_sex_desc := pc_sex_desc;
END IF;

dbpk_debug.msg('Obtaining destn ref for sex id %s',ln_sex_id);


dbpk_common.dbp_destn_ref ( 'IDM'
,'PERSON_SEX'
,lc_sex_code
,lc_sex_desc
,'IMS'
,ln_sex_id
,lc_destn_desc );

etc etc
39
oracledba
Debugging in the database

.co.uk
• Automatic tracking of
– module name
– line number
• Efficient
– supports approx. 5000 executions per second
• External tracking
– view messages in CLIENT_INFO field from any other session
– can dynamically write to file if required
• Linked in with trace
– trace facilities also controlled with same procedure

40
oracledba
Database Trace for Developers

.co.uk
• "dbpk_debug" controlled with the "init" procedure
SQL> desc TRACE_MODULES
Name Null? Type
----------------------- -------- -------------
USER_SESSION NOT NULL VARCHAR2(30)
TRACE_LEVEL NUMBER(2)
DEBUG_FILE VARCHAR2(100)
DEBUG_DIR VARCHAR2(100)
DEBUG_LEVEL NUMBER(2)

SQL> exec dbpk_debug.init('PD12345',1);


Turn on sql trace for anything run by user PD12345
SQL> exec dbpk_debug.init('35-1543', 12);
Turn on level 12 trace for the current session SID=35, SERIAL# = 1543

41
oracledba
Database Trace for Developers

.co.uk
SQL> begin
2 dbpk_debug.init('PD12345',
3 '/tmp','debug.dat',
4 dbpk_debug.debug_on);
5 end;
6 / Write debug calls to file for anything run by user PD12345

SQL> begin
2 dbpk_debug.init('35-1342',
3 '/tmp','debug.dat',
4 dbpk_debug.debug_off);
5 end;
6 / Stop writing debug information to file for session 35,1342
42
oracledba
Database Trace for Developers

.co.uk
SQL> set serveroutout on
SQL> exec DBPK_DEBUG.SHOW_SESSIONS

Session User Module Status


---------- ---------- ------------------ ----------------------
7-28105 IMS Idle for 4097 secs
9-47803 IMS SQL*Plus Idle for 274 secs
15-58197 PD71176 IMSF8220 Idle for 0 secs
18-14543 PD71953 IMSF1100 Idle for 445 secs
19-9720 IMS Idle for 170906 secs
23-16831 IMS Idle for 834 secs
24-39498 IMS SQL*Plus Idle for 36 secs
25-16854 IMS Idle for 3153 secs
26-5276 IMSWAPS SQL*Plus Currently running SQL
27-42288 IMS Idle for 73539 secs
28-59199 IMS T.O.A.D. Idle for 1421 secs
29-44907 PD71404 WAPF0100 Idle for 2674 secs
30-15146 IMS Idle for 72920 secs

43
oracledba
Database Trace for Developers

.co.uk
SQL> select * from all_trace_files;

USER_SESSION FILENAME DT
------------------ ------------------------------ ---------
10-38245 im1dev_ora_23246.trc 16/OCT/03
26-5276 im1dev_ora_15905.trc 16/OCT/03
PD71986 im1dev_ora_23296.trc 16/OCT/03

SQL> @gettrace
Enter value for user_session: 10-38256

INFO
-------------------------------------
Processing file im1dev_ora_23246.trc

PL/SQL procedure successfully completed.


TKPROF: Release 8.1.7.0.0 - Production on Thu Jul 17 16:19:36 2003

Trace file: im1dev_ora_23246.trc


Sort options: default
44
etc
oracledba
Database Trace for Developers

.co.uk
SQL> @getdebug
Enter value for file: /tmp/debug.dat

INFO
-------------------------------------
Processing file /tmp/debug.dat

PL/SQL procedure successfully completed.

(appears in notepad)

45
oracledba
Debugging in Forms

.co.uk
• Forms counterpart lk_debug
lk_debug.msg(m=>'Jumping to CTRL_ABC');

lk_debug.msg('10','WHEN-NEW-FORM-INSTANCE',
m=>'Jumping to CTRL_ABC');

• Will be controlled with lk_debug. init


lk_debug.init(
pv_module=>'IMSF0420',
pv_user=>'*',
pv_file=>'my_forms_file_name',
pv_dir=>'/apps/ims',
pn_debug_level=>lk_debug.debug_on);

46
oracledba
Error handling

.co.uk
• Guideline #1
– It is an EXCEPTION HANDLER
– If you can take remedial action
• include the handler
– If you get no value from handling the error
• do NOT handle it
– The calling level is the only routine that needs handlers

47
oracledba
Guideline #1

.co.uk
procedure PROC1(p_nom_id number, p_nom_date OUT date) is
begin
select nom_date_from
into p_nom_date
from nominal Problem with the query?
where nom_id = p_nom_id; Data integrity problem?

exception
when too_many_rows then
Maybe ok?
p_nom_date := null;
Is NOM_DATE_FROM nullable?
when no_data_found then
Have we just created work for caller?
p_nom_date := null;
when others then
raise; Waste of code – gains nothing
end;

48
oracledba
Error handling

.co.uk
• Guideline #2
– PL/SQL programs are single logical units of work
– Do not interrupt transaction flow

49
oracledba
Guideline #2

.co.uk
procedure PROC2(p_nom_id number) is
x number;
begin
insert into NOMINAL values (p_nom_id);

insert into NOM_AUDIT values (p_nom_id);

x := 1 / 0;

update RECORD_COUNT set CNT = CNT + 1;

exception Anything wrong here ?


when others then
rollback;
end;

50
oracledba
Guideline #2

.co.uk
WHEN-BUTTON-PRESSED

begin
post;
delete from OLD_NOM where NOM_ID = :block.nom_id;
proc2;
update OTHER_TABLE set OTHER_COLUMNS = …
end;

Data corruption

51
oracledba
Guideline #2

.co.uk
procedure PROC2(p_nom_id number) is
x number;
begin
insert into NOMINAL values (p_nom_id);
insert into NOM_AUDIT values (p_nom_id);
x := 1 / 0;
update RECORD_COUNT set CNT = CNT + 1;
end;

SQL> exec PROC2

ORA-01476: divisor is equal to zero

What reparative action is needed ?

NONE !!!
52
oracledba
Error handling

.co.uk
• Guideline #3
– Return codes are bad bad news
– Breaks rule number #2

53
oracledba
Guideline #3

.co.uk
procedure PROC2(p_nom_id number, p_ret_code OUT number) is
x number;
begin
insert into NOMINAL values (p_nom_id);
insert into NOM_AUDIT values (p_nom_id);
x := 1 / 0;
update RECORD_COUNT set CNT = CNT + 1;

p_ret_code := 0;
exception
when others then
p_ret_code := 1;
end;

54
oracledba
Guideline #3

.co.uk
WHEN-BUTTON-PRESSED

declare
ln_err_code number;
begin
PROC2(:block.nom_id, ln_err_code);

if ln_err_code = 1 then

What do I here ?
- don't know why it fell over (no error code)
- I've got a massive transaction mess (two
pending inserts that the trigger does not
know about)
- if I raise a new exception, I obfuscate the
location of where the code failed

55
oracledba
Error handling

.co.uk
• Guideline #4
– Re-cast errors only if you provide additional information

56
oracledba
Guideline #4

.co.uk
procedure PROC1(p_nom_id number, p_nom_date OUT date) is
l_error_pos number;
begin
l_error_pos := 10;
select nom_date_from We gain nothing over what Oracle
into p_nom_date would have given us anyway
from nominal
where nom_id = p_nom_id;

exception
when too_many_rows then
raise_application_error(-20000,
'TOO_MANY_ROWS error at pos '||l_error_pos||' in PROC1');
end;

57
oracledba
Guideline #4

.co.uk
procedure PROC1(p_nom_id number, p_nom_date OUT date) is
l_error_pos number;
begin
l_error_pos := 10;
select nom_date_from
into p_nom_date Now we know the offending row
from nominal
where nom_id = p_nom_id;

exception
when too_many_rows then
raise_application_error(-20000,
'TOO_MANY_ROWS for NOM_ID='||p_nom_id);
end;

58
oracledba
Error handling

.co.uk
• Guideline #5
– If you need to close cursors, your code is probably wrong

59
oracledba
Guideline #5

.co.uk
procedure PROC2(p_nom_id number) is
cursor CUR1 is …
cursor CUR2 is …
begin Waste of code and effort

exception
when others then
if CUR1%IS_OPEN then close CUR1; end if;
if CUR2%IS_OPEN then close CUR1; end if;
raise;
end;

60
oracledba
Guideline #5

.co.uk
package PKG1
cursor CUR1 is …
cursor CUR2 is …
procedure PROC2; Valid but were those cursors
end; really needed in the package?
package body PKG1
procedure PROC2(p_nom_id number) is
begin


exception
when others then
if CUR1%IS_OPEN then close CUR1; end if;
if CUR2%IS_OPEN then close CUR1; end if;
raise;
end;
end;
61

You might also like