Transcript An introduction to SQL*Trace, TKPROF and Execution Plans
An introduction to SQL*Trace, TKPROF and Execution Plans
David Kurtz Go-Faster Consultancy Ltd.
www.go-faster.co.uk
1
Resources
• • If you can’t hear me say so now.
Please feel free to ask questions as we go along.
• The presentation will be available from • • www.ukoug.org
www.go-faster.co.uk
www.go-faster.co.uk
2
Who am I?
• • • • DBA – Independent consultant System Performance tuning – PeopleSoft ERP – Oracle RDBMS UK Oracle User Group – Unix SIG Oak Table – www.oaktable.net
• Book – www.go-faster.co.uk
www.psftdba.com
3
UKOUG Unix SIG
• Next Meeting – 26 th May 2005 • Midlands – www.ukoug.org
• What are you going to present?
• RDBMS SIG – 15 th March 2005 • Slough • RAC SIG – 16 th June 2005 www.go-faster.co.uk
4
Agenda
• • • SQL Trace Execution Plans Timing Information • How to use these to solve performance problems.
www.go-faster.co.uk
5
Motivation
• Performance problems are instinctively routed to the DBA • • Trace can will locate a database problem It will prove that a problems IS NOT a database problem.
www.go-faster.co.uk
6
YAPP
• R = S + W – Where • • R = response time S = service time • W = wait time – Yet Another Performance Profiling Method • • • Anjo Kolk Shari Yamaguchi Jim Viscusi www.go-faster.co.uk
7
‘A Practitioners Guide to Optimizing Response Time’
• Optimizing Oracle Performance • Cary Millsap – • O’Reilly with Jeff Holt • www.hotsos.com
www.go-faster.co.uk
8
Another book – also recommended by Cary Millsap
• The Goal: A Process of Ongoing Improvement • Eliyahu Goldratt, Jeff Cox www.go-faster.co.uk
9
Aphorism
Performance is exactly what the user perceives it to be. No more, no less.
Performance is ‘poor’ when the user’s perception does not match their expectation.
www.go-faster.co.uk
10
Identify your bottlenecks
Performance Tuning is a search for lost time.
Time lost at a bottleneck is not just time lost at a bottleneck, it affects the whole system.
If it isn’t a problem, or it isn’t going to be a problem, then don’t tune it.
www.go-faster.co.uk
11
What is SQL trace?
• • • Session or database level Oracle shadow process writes to a text file in
user_dump_dest
.
Trace file contains – User and recursive SQL statements – – – Execution plan, physical & logical reads Timing information Wait and bind information (optional) www.go-faster.co.uk
12
What is SQL trace?
• • • First appeared in Oracle 6.
More instrumentation added at each release.
Not friendly format, can be read by humans.
– And sometimes that is necessary – Metalink note 39817.1
details structure of trace files • Usually process it with
tkprof
www.go-faster.co.uk
13
So what should I trace?
• • If I know which business transactions are my bottleneck… …and if I understand the structure of the application in question… • then I can determine which session I should trace and when I should trace it.
www.go-faster.co.uk
14
Initialisation parameters
• • • • • timed_statistics = TRUE user_dump_dest = '
15
timed_statistics = TRUE
• You must set this initialisation variable to true – otherwise you won’t get any timing information anywhere in the database – including the SQL trace files – Low overhead – Can be set at session level –
Recommend always set it true
www.go-faster.co.uk
16
max_dump_file_size
• Be careful that your trace files are not truncated. – look at tail for message • DUMP FILE SIZE IS LIMITED – Your file may be truncated prior to the point of interest.
– Parameter expressed in O/S blocks, Kb, or Mb – Dynamic parameter from Oracle 9.x
www.go-faster.co.uk
17
_trace_files_public = TRUE
• This parameter controls the OS permission of the trace file.
– Setting it true allows the trace file to be read outside the DBA group – Not dynamically alterable. – Consider security issue.
www.go-faster.co.uk
18
tracefile_identifier =
• Set at init.ora or setting level – Available from Oracle 8.1.7
– Trace file identifier string appended to name of trace file – Can alter after starting trace, and so get two trace files.
– Do not put space ( ) or hyphen (-) in the identifier. You get an invalid file error.
www.go-faster.co.uk
19
tracefile_identifier =
ALTER SESSION SET TRACE_FILE_IDENTIFIER = ‘nVision_Report_NVSRUN_159’; /u01/app/oracle/admin/F84SP1/udump/ f84sp1_ora_41776_nVision_Report_NVSRUN_159 .trc
www.go-faster.co.uk
20
How to enable SQL trace
• From UKOUG2002 – Advanced Oracle Diagnostics • Julian Dyke – www.juliandyke.com
– 10 methods of enabling trace information in Oracle www.go-faster.co.uk
21
How to enable SQL trace
ALTER SESSION SET EVENTS '10046 trace name context forever, level
Level 0 1 4 8 12 Description Disabled Same as ALTER SESSION SET SQL_TRACE=TRUE Include bind variable information Include wait statistics Include bind variable and wait statistics
www.go-faster.co.uk
22
How to enable SQL trace
• At instance level # Enable SQL trace for instance sql_trace = TRUE – or # Enable SQL*trace with binds for instance event = '10046 trace name context forever, level 4'; www.go-faster.co.uk
23
How to disable SQL trace
• SQL Trace parameter cannot be altered directly --Enable SQL trace for instance ALTER SYSTEM SET EVENTS '10046 trace name context forever, level 1; – or --Disable trace for instance ALTER SYSTEM SET EVENTS '10046 trace name context off'; www.go-faster.co.uk
24
How to enable SQL trace
• Either --Enable SQL trace for instance ALTER SYSTEM SET SQL_TRACE=TRUE; • or --Disable trace for instance ALTER SYSTEM SET SQL_TRACE=FALSE; www.go-faster.co.uk
25
How to enable SQL trace
• In current session with supplied PL/SQL procedures ( --Enable SQL trace for session DBMS_SESSION.SET_SQL_TRACE
FLAG BOOLEAN -- TRUE to enable; -- FALSE to disable ); www.go-faster.co.uk
26
How to enable SQL trace
• In current session ( --Enable SQL trace for session DBMS_SUPPORT.START_TRACE
WAITS BOOLEAN, -- Include waits (default FALSE) BINDS BOOLEAN -- Include binds (default FALSE) ); --Disable SQL Trace for session DBMS_SUPPORT.STOP_TRACE; www.go-faster.co.uk
27
How to enable SQL trace
• In another session ( DBMS_SYSTEM.SET_SQL_TRACE_IN_SESSION
SI NUMBER, SE NUMBER, -- SID -- Serial Number SQL_TRACE BOOLEAN -- TRUE to enable; -- FALSE to disable ); • SID and SERIAL# from V$SESSION.
www.go-faster.co.uk
28
How to enable SQL trace
• In another session ( DBMS_SUPPORT.START_TRACE_IN_SESSION
SI NUMBER, SE NUMBER, -- SID -- Serial Number (can be 0) WAITS BOOLEAN, -- Include waits (default FALSE) BINDS BOOLEAN -- Include binds (default FALSE) ); www.go-faster.co.uk
29
How to disable SQL trace
• In another session ( DBMS_SUPPORT.STOP_TRACE_IN_SESSION
SI NUMBER, SE NUMBER, -- SID -- Serial Number (can be 0) ); www.go-faster.co.uk
30
How to enable SQL trace
• Set event in another session • ( DBMS_SYSTEM.SET_EV
SI NUMBER, SE NUMBER, EV NUMBER, LE NUMBER, NM VARCHAR2 ); -- SID -- Serial Number (can be 0) -- Event Number e.g. 10046 -- Level e.g. 4 -- Action Name – can be '‘ Disable with level 0 www.go-faster.co.uk
31
New in Oracle 10g
• In another session ( DBMS_MONITOR.SESSION_TRACE_ENABLE
SI NUMBER, SE NUMBER, -- SID -- Serial Number (can be 0) WAITS BOOLEAN, -- Include waits (default FALSE) BINDS BOOLEAN -- Include binds (default FALSE) ); www.go-faster.co.uk
32
New in Oracle 10g
• In another session ( DBMS_MONITOR.SESSION_TRACE_DISABLE
SI NUMBER, SE NUMBER, -- SID -- Serial Number (can be 0) ); www.go-faster.co.uk
33
Using logon triggers to enable SQL trace
• Login trigger to trace from the very beginning.
CREATE OR REPLACE TRIGGER sys.trace_logon_sysadm
AFTER LOGON ON sysadm.schema
BEGIN sys.dbms_session.set_sql_trace(true); END; / www.go-faster.co.uk
34
Using triggers to enable SQL trace (i)
• Trigger fired by starting process.
CREATE OR REPLACE TRIGGER sysadm.set_trace AFTER UPDATE OF runstatus ON sysadm.psprcsrqst FOR EACH ROW WHEN (new.runstatus = 7 and old.runstatus != 7 AND new.prcstype IN('Application Engine','COBOL SQL','Crystal','nVision-Report','SQR Process','SQR Report','SQR Report For WF Delivery') AND new.prcsname = ‘GPPDPRUN’ AND new.begindttm <= TO_DATE('200503111800','YYYYMMDDHH24MI')) www.go-faster.co.uk
35
Using triggers to enable SQL trace (ii)
BEGIN EXECUTE IMMEDIATE 'ALTER SESSION SET TIMED_STATISTICS = TRUE'; EXECUTE IMMEDIATE 'ALTER SESSION SET MAX_DUMP_FILE_SIZE = UNLIMITED'; EXECUTE IMMEDIATE 'ALTER SESSION SET TRACEFILE_IDENTIFIER = '''|| END; TRANSLATE(:new.prcstype||'_'||:new.prcsname,' -','__')||'_'|| :new.prcsinstance||''''; EXECUTE IMMEDIATE 'ALTER SESSION SET EVENTS ''10046 trace name context forever, level 8'''; / www.go-faster.co.uk
36
What is in the SQL trace file
• See Metalink Note 39817.1
for details of trace file structure www.go-faster.co.uk
37
SQL trace file sections
• Trace Sections – – – DBMS_APPLICATION_INFO settings Cursors Operations • Parse, exec, fetch, (sort) unmap – – Errors Stat • Execution Plans – Xctend • End of transaction www.go-faster.co.uk
38
SQL trace file sections
• With event 10046 – Binds • (level 4) – Waits • (level 8) • Timings – – centisecond timings (Oracle 7 & 8) microsecond from Oracle 9 www.go-faster.co.uk
39
SQL trace file contents
/u01/app/oracle/admin/F84SP1/udump/f84sp1_ora_41776_nVision_Report _NVSRUN_159.trc
… Oracle9i Enterprise Edition Release 9.2.0.1.0 - 64bit Production JServer Release 9.2.0.1.0 - Production ORACLE_HOME = /u01/app/oracle/product/9.2.0
System name: AIX Node name: xxxxxxxxx Release: 3 Version: 4 Machine: 0000C6BF4C00 Instance name: F84SP1 Redo thread mounted by this instance: 1 Oracle process number: 28 Unix process pid: 41776, image: oracle@xxxxxxxxx (TNS V1-V3) www.go-faster.co.uk
40
SQL trace file contents
PARSING IN CURSOR #3 len=58 dep=0 uid=24 oct=3 lid=24 tim=1045288408856870 hv=2952492898 ad='3b36970' SELECT VERSION FROM PSVERSION WHERE OBJECTTYPENAME = 'SYS' END OF STMT PARSE #3:c=0,e=1836,p=0,cr=0,cu=0,mis=1,r=0,dep=0,og=4, tim=1045288408856862 EXEC #3:c=0,e=80,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=4, tim=1045288408857230 WAIT #3: nam='SQL*Net message to client' ela= 3 p1=1413697536 p2=1 p3=0 FETCH #3:c=0,e=75,p=0,cr=2,cu=0,mis=0,r=1,dep=0,og=4, tim=1045288408857420 WAIT #3: nam='SQL*Net message from client' ela= 47544 p1=1413697536 p2=1 p3=0 STAT #3 id=1 cnt=1 pid=0 pos=1 obj=31453 op='TABLE ACCESS BY INDEX ROWID PSVERSION ' STAT #3 id=2 cnt=1 pid=1 pos=1 obj=31454 op='INDEX UNIQUE SCAN PS_PSVERSION ' www.go-faster.co.uk
41
• Oracle supplied utility – – – Transient Kernel Profiler Processes SQL trace files Provides a easy to read report • • • Timings Sorted by CPU or Elapsed Timings Wait analysis from Oracle 9 – Even on Oracle 8 trace!
• • Execution plans Aggregate identical statements www.go-faster.co.uk
tkprof
42
tkprof sample
SELECT VERSION FROM PSVERSION WHERE OBJECTTYPENAME = 'SYS' call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.00 0.00 0 0 0 0 Execute 1 0.00 0.00 0 0 0 0 Fetch 1 0.00 0.00 0 2 0 1 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 3 0.00 0.00 0 2 0 1 Misses in library cache during parse: 1 Optimizer goal: CHOOSE Parsing user id: 24 Rows Row Source Operation ------ -------------------------------------------------- 1 TABLE ACCESS BY INDEX ROWID PSVERSION 1 INDEX UNIQUE SCAN PS_PSVERSION (object id 31454) www.go-faster.co.uk
43
Row source statistics
• From Oracle 9.2.0.2 ALTER SESSION SET STATISTICS_LEVEL = ALL; – Added to SQL Trace stat line – Appears in tkprof output – Performance overhead www.go-faster.co.uk
44
Row source statistics
SELECT A.START_DATE, A.STOP_DATE FROM PS_X_PYE_OVRD_ET A WHERE A.EMPLID= :1 AND A.EMPL_RCD= :2 AND A.PIN_NUM= :3 AND A.START_DATE<= :4 AND A.STOP_DATE>= :5 AND A.START_DATE<= :6 ORDER BY A.START_DATE DESC call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.02 0.17 0 0 0 0 Execute 116759 20.76 40.24 0 0 0 0 Fetch 116759 25.60 88.40 1910 440408 0 89622 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 233519 46.38 128.81 1910 440408 0 89622 www.go-faster.co.uk
45
Row source statistics
Rows Row Source Operation ------ -------------------------------------------------- 89622 SORT ORDER BY (cr=440408 r=1910 w=0 time=72942929 us) 89622 PARTITION RANGE SINGLE PARTITION: KEY KEY (cr=440408 r=1910 w=0 time=58756548 us) 89622 TABLE ACCESS BY LOCAL INDEX ROWID OBJ#(165144) PARTITION: KEY KEY (cr=440408 r=1910 w=0 time=57904868 us) 89622 INDEX RANGE SCAN DESCENDING OBJ#(166035) PARTITION: KEY KEY (cr=350786 r=451 w=0 time=20700497 us) (object id 166035) www.go-faster.co.uk
46
How to tune with tkprof
• Identify your bottlenecks – Decide what to trace – Enable SQL trace – Tkprof • • • • Sort=(fchela,exeela,prsela) Waits=yes Print=10 Explain=
47
Example 1: SQL Problem
• • • You have traced your process… you run tkprof… And at the top of the report you have a big block of SQL.
• What do you do next?
www.go-faster.co.uk
48
SQL statement
INSERT INTO PS_PP_CUST_TMP2 ( PROCESS_INSTANCE, DEPOSIT_BU, DEPOSIT_ID, PAYMENT_SEQ_NUM, CUST_ID, PAYMENT_AMT, PAYMENT_DT, PP_METHOD, SETID, SUBCUST_QUAL1, SUBCUST_QUAL2, PP_HOLD, PP_MET_SW, PAYMENT_CURRENCY ) SELECT DISTINCT P.PROCESS_INSTANCE, P.DEPOSIT_BU, P.DEPOSIT_ID, P.PAYMENT_SEQ_NUM, C.CUST_ID, P.PAYMENT_AMT, P.PAYMENT_DT, O.PP_METHOD, O.SETID, C.SUBCUST_QUAL1, C.SUBCUST_QUAL2, O.PP_HOLD, 'N', P.PAYMENT_CURRENCY FROM PS_CUST_OPTION O, PS_ITEM I, PS_CUSTOMER C, PS_SET_CNTRL_REC S, PS_PAYMENT_ID_ITEM X, PS_PP_PAYMENT_TMP P WHERE P.PROCESS_INSTANCE = 212 AND S.RECNAME = 'CUSTOMER' AND S.SETID = C.SETID AND S.SETCNTRLVALUE = I.BUSINESS_UNIT AND I.CUST_ID = C.CUST_ID AND I.ITEM_STATUS = 'O' AND O.SETID = C.REMIT_FROM_SETID AND O.CUST_ID = C.REMIT_FROM_CUST_ID AND O.EFFDT = ( SELECT MAX(Z.EFFDT) FROM PS_CUST_OPTION Z WHERE Z.SETID = O.SETID AND Z.CUST_ID = O.CUST_ID AND Z.EFF_STATUS = 'A' AND Z.EFFDT <= P.PAYMENT_DT ) AND O.PP_METHOD <> ' ' AND P.DEPOSIT_BU = X.DEPOSIT_BU AND P.DEPOSIT_ID = X.DEPOSIT_ID AND P.PAYMENT_SEQ_NUM = X.PAYMENT_SEQ_NUM AND X.REF_QUALIFIER_CODE = 'I' AND X.REF_VALUE = I.ITEM
www.go-faster.co.uk
49
Statistics
… count = number of times OCI procedure was executed cpu = cpu time in seconds executing elapsed = elapsed time in seconds executing disk = number of physical reads of buffers from disk query = number of buffers gotten for consistent read current = number of buffers gotten in current mode (usually for update) rows = number of rows processed by the fetch or execute call … call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.31 0.33 4 0 4 0 Execute 1 156.61 160.23 164769 3981545 0 0 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 2 156.92 160.56 164773 3981545 4 0 www.go-faster.co.uk
50
Execution plan (from stat lines)
Rows Execution Plan ------ -------------------------------------------------- 0 INSERT STATEMENT GOAL: CHOOSE 0 SORT (UNIQUE) 0 FILTER 0 NESTED LOOPS 8 NESTED LOOPS 1000040 NESTED LOOPS 360 NESTED LOOPS 10 NESTED LOOPS 10 TABLE ACCESS BY INDEX ROWID PS_PP_PAYMENT_TMP 11 INDEX (RANGE SCAN) (object id 9329) 20 INDEX (RANGE SCAN) OF (object id 8105) 360 TABLE ACCESS (BY INDEX ROWID) OF 'PS_SET_CNTRL_REC' 370 INDEX (RANGE SCAN) OF (object id 12020) 1000040 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUSTOMER' 1000400 INDEX (RANGE SCAN) OF (object id 4751) 1000048 INDEX (RANGE SCAN) OF 'PS#ITEM' (NON-UNIQUE) 8 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' 16 INDEX (RANGE SCAN) OF (object id 4854) 0 SORT (AGGREGATE) 0 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' 0 INDEX (RANGE SCAN) OF (object id 4854) www.go-faster.co.uk
51
Execution plan (if you connect tkprof to the database)
Rows Execution Plan ------ -------------------------------------------------- 0 INSERT STATEMENT GOAL: CHOOSE 0 SORT (UNIQUE) 0 FILTER 0 NESTED LOOPS 8 NESTED LOOPS 1000040 NESTED LOOPS 360 NESTED LOOPS 10 NESTED LOOPS 10 TABLE ACCESS (BY INDEX ROWID) OF 'PS_PP_PAYMENT_TMP' 11 INDEX (RANGE SCAN) OF 'PSAPP_PAYMENT_TMP' (NON-UNIQUE) 20 INDEX (RANGE SCAN) OF 'PSAPAYMENT_ID_ITEM' (NON-UNIQUE) 360 TABLE ACCESS (BY INDEX ROWID) OF 'PS_SET_CNTRL_REC' 370 INDEX (RANGE SCAN) OF 'PSBSET_CNTRL_REC' (NON-UNIQUE) 1000040 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUSTOMER' 1000400 INDEX (RANGE SCAN) OF 'PS#CUSTOMER' (NON-UNIQUE) 1000048 INDEX (RANGE SCAN) OF 'PS#ITEM' (NON-UNIQUE) 8 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' 16 INDEX (RANGE SCAN) OF 'PS_CUST_OPTION' (UNIQUE) 0 SORT (AGGREGATE) 0 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' 0 INDEX (RANGE SCAN) OF 'PS_CUST_OPTION' (UNIQUE) www.go-faster.co.uk
52
1. Make the statement readable
SELECT DISTINCT P.PROCESS_INSTANCE, P.DEPOSIT_BU, P.DEPOSIT_ID, P.PAYMENT_SEQ_NUM, C.CUST_ID, P.PAYMENT_AMT, P.PAYMENT_DT, O.PP_METHOD, O.SETID, C.SUBCUST_QUAL1, C.SUBCUST_QUAL2, O.PP_HOLD, 'N', P.PAYMENT_CURRENCY FROM PS_CUST_OPTION O, PS_ITEM I, PS_CUSTOMER C, PS_SET_CNTRL_REC S, PS_PAYMENT_ID_ITEM X, PS_PP_PAYMENT_TMP P WHERE AND AND AND P.PROCESS_INSTANCE = 212 S.RECNAME = 'CUSTOMER' S.SETID = C.SETID S.SETCNTRLVALUE = I.BUSINESS_UNIT AND AND AND AND AND I.CUST_ID = C.CUST_ID I.ITEM_STATUS = 'O' O.SETID = C.REMIT_FROM_SETID O.CUST_ID = C.REMIT_FROM_CUST_ID O.EFFDT = ( SELECT FROM MAX(Z.EFFDT) PS_CUST_OPTION Z WHERE AND AND AND AND O.PP_METHOD <> ' ' Z.SETID = O.SETID Z.CUST_ID = O.CUST_ID Z.EFF_STATUS = 'A' Z.EFFDT <= P.PAYMENT_DT) AND P.DEPOSIT_BU = X.DEPOSIT_BU AND P.DEPOSIT_ID = X.DEPOSIT_ID AND P.PAYMENT_SEQ_NUM = X.PAYMENT_SEQ_NUM AND X.REF_QUALIFIER_CODE = 'I' AND X.REF_VALUE = I.ITEM
www.go-faster.co.uk
53
PP_METHOD <> ' '
2. Start to draw the query
EFFDT
PS_CUST_OPTION (O)
RECNAME = 'CUSTOMER' O.SETID = C.REMIT_FROM_SETID O.CUST_ID = C.REMIT_FROM_CUST_ID SETID
PS_CUSTOMER (C)
CUST_ID
PS_SET_CNTRL_REC (S)
REF_QUALIFIER_CODE = 'I' S.SETCNTRLVALUE = I.BUSINESS_UNIT
PS_ITEM (I)
X.REF_VALUE = I.ITEM
I.ITEM_STATUS = 'O'
PS_PAYMENT_ID_ITEM (X)
P.DEPOSIT_BU = X.DEPOSIT_BU P.DEPOSIT_ID = X.DEPOSIT_ID
P.PAYMENT_SEQ_NUM = X.PAYMENT_SEQ_NUM
www.go-faster.co.uk
PS_PP_PAYMENT_TMP (P)
54 PROCESS_INSTANCE = 212
4. Get the order from the plan
0 FILTER 0 NESTED LOOPS 8 NESTED LOOPS 1000040 NESTED LOOPS 360 NESTED LOOPS 10 NESTED LOOPS 10 (1) TABLE ACCESS (BY INDEX ROWID) OF 'PS_PP_PAYMENT_TMP' 11 INDEX (RANGE SCAN) OF 'PSAPP_PAYMENT_TMP' (NON-UNIQUE) 20 (2) INDEX (RANGE SCAN) OF 'PSAPAYMENT_ID_ITEM' (NON-UNIQUE) 360 (3) TABLE ACCESS (BY INDEX ROWID) OF 'PS_SET_CNTRL_REC' 370 INDEX (RANGE SCAN) OF 'PSBSET_CNTRL_REC' (NON-UNIQUE) 1000040 (4) TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUSTOMER' 1000400 INDEX (RANGE SCAN) OF 'PS#CUSTOMER' (NON-UNIQUE) 1000048 (5) INDEX (RANGE SCAN) OF 'PS#ITEM' (NON-UNIQUE) 8 (6) TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' 16 INDEX (RANGE SCAN) OF 'PS_CUST_OPTION' (UNIQUE) 0 SORT (AGGREGATE) 0 TABLE ACCESS (BY INDEX ROWID) OF 'PS_CUST_OPTION' INDEX (RANGE SCAN) OF 'PS_CUST_OPTION' (UNIQUE) www.go-faster.co.uk
55
5. Put the order in the diagram
PP_METHOD <> ' ' EFFDT RECNAME = 'CUSTOMER' O.SETID = C.REMIT_FROM_SETID O.CUST_ID = C.REMIT_FROM_CUST_ID SETID S.SETCNTRLVALUE = I.BUSINESS_UNIT
CUST_ID REF_QUALIFIER_CODE = 'I' X.REF_VALUE = I.ITEM
I.ITEM_STATUS = 'O' P.DEPOSIT_BU = X.DEPOSIT_BU P.DEPOSIT_ID = X.DEPOSIT_ID
P.PAYMENT_SEQ_NUM = X.PAYMENT_SEQ_NUM
www.go-faster.co.uk
56 PROCESS_INSTANCE = 212
6. This time, the answer is an index
CREATE INDEX PSBITEM ON PS_ITEM (ITEM, CUST_ID, BUSINESS_UNIT, ITEM_STATUS) TABLESPACE PSINDEX STORAGE (INITIAL 10K NEXT 98K MAXEXTENTS 110 PCTINCREASE 0) / www.go-faster.co.uk
57
PP_METHOD <> ' ' RECNAME = 'CUSTOMER' EFFDT
New Execution Order
O.SETID = C.REMIT_FROM_SETID O.CUST_ID = C.REMIT_FROM_CUST_ID SETID S.SETCNTRLVALUE = I.BUSINESS_UNIT
CUST_ID REF_QUALIFIER_CODE = 'I' X.REF_VALUE = I.ITEM
I.ITEM_STATUS = 'O' P.DEPOSIT_BU = X.DEPOSIT_BU P.DEPOSIT_ID = X.DEPOSIT_ID
P.PAYMENT_SEQ_NUM = X.PAYMENT_SEQ_NUM
www.go-faster.co.uk
58 PROCESS_INSTANCE = 212
Statistics
Before call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.31 0.33 4 0 4 0 Execute 1 156.61 160.23 164769 3981545 0 0 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 2 156.92 160.56 164773 3981545 4 0 After call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.35 2.56 3 0 3 0 Execute 1 0.03 0.05 38 289 3 0 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 2 0.38 2.61 41 289 6 0 www.go-faster.co.uk
59
Example 2: Wait Events
• • How do you know it’s not the database?
Event 10046,8 – enable wait information.
www.go-faster.co.uk
60
CPU –v- elapsed time
INSERT /*GPPRDMGR_I_ACUM*/ INTO PS_GP_RSLT_ACUM (CAL_RUN_ID ,EMPLID ,EMPL_RCD ,GP_PAYGROUP ,CAL_ID ,RSLT_SEG_NUM ,PIN_NUM ,EMPL_RCD_ACUM ,ACM_FROM_DT , ACM_THRU_DT ,USER_KEY1 ,USER_KEY2 ,USER_KEY3 ,USER_KEY4 ,SLICE_BGN_DT , SLICE_END_DT ,COUNTRY ,ACM_TYPE ,ACM_PRD_OPTN ,CALC_RSLT_VAL ,CALC_VAL , USER_ADJ_VAL ,PIN_PARENT_NUM ,CORR_RTO_IND ) VALUES (:1,:2,:3,:4,:5,:6,:7,:8,:9,:10,:11,:12,:13,:14,:15,:16,:17,:18,:19,:20,:21, :22,:23,:24) call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.00 0.00 0 0 0 0 Execute 22510 73.30 1269.24 31542 45040 503607 558966 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 22511 73.30 1269.24 31542 45040 503607 558966 www.go-faster.co.uk
61
Wait events report discrepancy
Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------- Waited --------- ----------- SQL*Net more data from client 27495 0.56 1036.26
db file sequential read 31542 0.97 148.99
SQL*Net message from client 22510 0.44 80.41
free buffer waits 19 1.02 4.74
SQL*Net message to client 22510 0.01 0.08
latch free 5 0.02 0.08
buffer busy waits 1 0.00 0.00
log file switch completion 1 0.06 0.06
www.go-faster.co.uk
62
After resolving network problem
call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.00 0.00 0 0 0 0 Execute 22264 103.07 113.04 2521 86624 553966 662676 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 22265 103.07 113.04 2521 86624 553966 662676 Event waited on Times Max. Wait Total Waited ---------------------------- Waited --------- ----------- SQL*Net message from client 22264 0.47 88.84
SQL*Net more data from client 29138 0.47 6.69
www.go-faster.co.uk
63
Example 3: Waits events
UPDATE /*GPPDPDM4_U_TRIGGER*/ PS_GP_SEG_TRGR SET CAL_RUN_ID =:1 WHERE TRGR_EFFDT>=:2 AND TRGR_EFFDT<=:3 AND EMPLID=:4 AND COUNTRY=:5 AND SEG_TRGR_STATUS='A' AND CAL_RUN_ID=' ' AND (EMPL_RCD=:6 OR SEG_TRGR_LVL='E') AND TRGR_EVENT_ID IN (SELECT SEC.TRGR_EVENT_ID FROM PS_GP_SEG_EVT SEC WHERE SEC.SEG_TYPE='P' AND SEC.COUNTRY=:7 ) call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 5858 0.57 0.51 0 0 0 0 Execute 27973 7.60 1989.00 1630 95825 662 645 Fetch 0 0.00 0.00 0 0 0 0 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 33831 8.17 1989.52 1630 95825 662 645 www.go-faster.co.uk
64
Wait Events
Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited -------------------------- Waited --------- ----------- enqueue 658 3.34 1973.10
SQL*Net message from client 27973 1.34 99.10
db file sequential read 1630 0.27 8.67
SQL*Net message to client 27973 0.00 0.05
latch free 2 0.00 0.00
www.go-faster.co.uk
65
Example 4: Idle wait?
• SQL*Net message from client – Often call an idle wait – It means that the database is idle – What is a ‘batch’ process?
www.go-faster.co.uk
66
What is a ‘batch’ process?
• It is a process that runs for a period of time without waiting for user input.
• So if the database is idle then the client process must be busy.
• SQL*Net message from client =Application busy time www.go-faster.co.uk
67
Summary at bottom of report
• Active process making lots of calls to the database OVERALL TOTALS FOR ALL NON-RECURSIVE STATEMENTS call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 12197 3.85 4.50 621 25979 0 0 Execute 870343 537.36 750.89 70625 18372702 2047141 2657717 Fetch 710951 405.99 917.94 229999 10341004 73 3030039 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 1593491 947.20 1673.34 301245 28739685 2047214 5687756 www.go-faster.co.uk
68
Is it the database?
Elapsed times include waiting on following events: Event waited on Times Max. Wait Total Waited ---------------------------- Waited --------- ----------- SQL*Net message to client 881285 0.01 1.68
SQL*Net message from client 881285 1.22 2491.24
log file sync 185 1.01 28.18
SQL*Net more data from client 62845 0.40 5.27
SQL*Net more data to client 21008 0.00 1.54
db file sequential read 201760 2.39 451.60
direct path write 2632 0.67 49.76
direct path read 4034 0.71 28.97
www.go-faster.co.uk
69
Is it the database?
• Perhaps this time we should look at the application Batch process elapsed time SQL*Net message from client Database Time Unaccounted for (CPU contention?) 4790 2491 1673 626 www.go-faster.co.uk
70
Example 5: tkprof can mislead
• Different plans – One from stat lines • How the statement was actually executed – One from ‘explain plan for’ command • How the analyser might execute the statement in the future on the basis of the current statistics • Some numbers can be nonsense www.go-faster.co.uk
71
A simple SQL statement
SELECT DISTINCT A.EMPLID, A.NATIONAL_ID FROM PS_PERS_NID A , PS_GP_PYE_STAT_WRK P WHERE P.CAL_RUN_ID =:1 AND P.EMPLID BETWEEN :2 AND :3 AND P.PRD_TYPE <> 'H' AND P.PYE_CALC_STAT < '50' AND P.EMPLID=A.EMPLID AND A.PRIMARY_NID= :4 ORDER BY A.EMPLID ASC call count cpu elapsed disk query current rows ------- ----- -------- ---------- ---------- ---------- --------- --------- Parse 1 0.00 0.00 0 0 0 0 Execute 5598 1.06 1.07 0 0 0 0 Fetch 5598 4411.76 4644.73 127 183871489 0 1117812 ------- ----- -------- ---------- ---------- ---------- --------- --------- total 11197 4412.82 4645.80 127 183871489 0 1117812 www.go-faster.co.uk
72
Plan from stat lines
Rows Row Source Operation ------ -------------------------------------------------- 1117812 SORT UNIQUE 44603520 NESTED LOOPS 68123268 PARTITION RANGE ITERATOR PARTITION: KEY KEY 68123268 TABLE ACCESS BY LOCAL INDEX ROWID PS_GP_PYE_STAT_WRK PARTITION: KEY KEY 68123268 INDEX RANGE SCAN PARTITION: KEY KEY (object id 273486) 44603520 TABLE ACCESS BY INDEX ROWID PS_PERS_NID 112721190 INDEX RANGE SCAN (object id 157793) www.go-faster.co.uk
73
Plan from ‘explain plan for’
Rows Execution Plan ------ -------------------------------------------------- 0 SELECT STATEMENT GOAL: CHOOSE 1117812 SORT (UNIQUE) 44603520 MERGE JOIN 68123268 TABLE ACCESS GOAL: ANALYZED (BY INDEX ROWID) OF 'PS_PERS_NID' 68123268 INDEX GOAL: ANALYZED (RANGE SCAN) OF 'PS_PERS_NID' (UNIQUE) 68123268 SORT (JOIN) 44603520 PARTITION RANGE (ITERATOR) PARTITION:KEYKEY 112721190 TABLE ACCESS GOAL: ANALYZED (BY LOCAL INDEX ROWID) OF 'PS_GP_PYE_STAT_WRK' PARTITION:KEYKEY 0 INDEX GOAL: ANALYZED (RANGE SCAN) OF 'PS_GP_PYE_STAT_WRK' (UNIQUE) PARTITION:KEYKEY www.go-faster.co.uk
74
Example 6: Transitive Closure
• • If A=B and B=C you can infer that A=C You and I can, but Oracle can’t do this on column predicates • • Oracle can do this on value predicates If A=1 and A=B, Oracle knows that B=1 www.go-faster.co.uk
75
A simple query?
SELECT ... FROM PS_GP_PYE_STAT_WRK S,PS_GP_PYE_PRC_STAT P2,PS_GP_RSLT_ACUM RA WHERE S.RUN_CNTL_ID=:1 AND S.OPRID=:2 AND S.EMPLID BETWEEN :3 AND :4 AND S.EMPLID=RA.EMPLID
AND P2.EMPLID=RA.EMPLID
AND S.EMPL_RCD=RA.EMPL_RCD
AND P2.EMPL_RCD=RA.EMPL_RCD
AND S.GP_PAYGROUP=RA.GP_PAYGROUP
AND P2.GP_PAYGROUP=RA.GP_PAYGROUP
AND S.CAL_ID=RA.CAL_ID
AND P2.CAL_ID=RA.CAL_ID
AND P2.CAL_RUN_ID=RA.CAL_RUN_ID
AND P2.ORIG_CAL_RUN_ID=RA.ORIG_CAL_RUN_ID
AND S.PRD_TYPE='R' AND S.RSLT_SEG_NUM=RA.RSLT_SEG_NUM
AND S.PRIOR_VER_NUM=P2.RSLT_VER_NUM
AND S.PRIOR_REV_NUM=P2.RSLT_REV_NUM
AND RA.ACM_PRD_OPTN='1'; www.go-faster.co.uk
76
A three table join
RUN_CNTL_ID=:1 OPRID=:2 :3 <= `EMPLID <= :4 PRD_TYPE='R' S.PRIOR_VER_NUM=P2.RSLT_VER_NUM
S.PRIOR_REV_NUM=P2.RSLT_REV_NUM
PS_GP_PYE_STAT_WRK (S) 1
EMPLID, EMPL_RCD, GP_PAYGROUP, CAL_ID, RSLT_SEG_NUM
PS_GP_PYE_PRC_STAT (P2) 3
EMPLID, EMPL_RCD, GP_PAYGROUP, CAL_RUN_ID, ORIG_CAL_RUN_ID, CAL_ID, RSLT_SEG_NUM
PS_GP_RSLT_ACUM (RA) 2
www.go-faster.co.uk
ACM_PRD_OPTN='1' 77
Index on GP_RSLT_ACUM
CREATE UNIQUE INDEX PS_GP_RSLT_ACUM ON PS_GP_RSLT_ACUM ( EMPLID , CAL_RUN_ID, EMPL_RCD , GP_PAYGROUP , CAL_ID , ORIG_CAL_RUN_ID, RSLT_SEG_NUM , PIN_NUM, EMPL_RCD_ACUM, ACM_FROM_DT, ACM_THRU_DT, SLICE_BGN_DT, SLICE_END_DT, SEQ_NUM8) ...
www.go-faster.co.uk
78
Explicitly add implicit joins
AND P2.EMPLID=S.EMPLID AND P2.EMPL_RCD=S.EMPL_RCD AND P2.GP_PAYGROUP=S.GP_PAYGROUP AND P2.CAL_ID=S.CAL_ID
www.go-faster.co.uk
79
With the extra index
RUN_CNTL_ID=:1 OPRID=:2 :3 <= `EMPLID <= :4 PRD_TYPE='R'
PS_GP_PYE_STAT_WRK (S) 1
EMPLID, EMPL_RCD, GP_PAYGROUP, CAL_ID S.PRIOR_VER_NUM=P2.RSLT_VER_NUM
S.PRIOR_REV_NUM=P2.RSLT_REV_NUM
EMPLID, EMPL_RCD, GP_PAYGROUP, CAL_ID, RSLT_SEG_NUM
PS_GP_PYE_PRC_STAT (P2) 2
EMPLID, EMPL_RCD, GP_PAYGROUP, CAL_RUN_ID, ORIG_CAL_RUN_ID, CAL_ID, RSLT_SEG_NUM
PS_GP_RSLT_ACUM (RA) 3
www.go-faster.co.uk
ACM_PRD_OPTN='1' 80
Index on GP_RSLT_ACUM
CREATE UNIQUE INDEX PS_GP_RSLT_ACUM ON PS_GP_RSLT_ACUM ( EMPLID , CAL_RUN_ID , EMPL_RCD , GP_PAYGROUP , CAL_ID , ORIG_CAL_RUN_ID , RSLT_SEG_NUM , PIN_NUM, EMPL_RCD_ACUM, ACM_FROM_DT, ACM_THRU_DT, SLICE_BGN_DT, SLICE_END_DT, SEQ_NUM8) ...
www.go-faster.co.uk
81
Conclusion
• • • How to think about performance issues IDENTIFY YOUR BOTTLENECKS SQL Trace – What to trace, How to enable, What’s in it?
• Tkprof – What can it tell you? When does it mislead?
www.go-faster.co.uk
82
Questions?
www.go-faster.co.uk
83
An introduction to SQL*Trace, TKPROF and Execution Plans
David Kurtz Go-Faster Consultancy Ltd.
www.go-faster.co.uk
84