performance tuning

26
File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 1 of 26 PERFORMANCE TUNING FOR FINANCIALS MAKING THE RULE- BASED OPTIMIZER WORK ASSIST Pty Ltd INTRODUCTION This paper has been written with the aim of assisting 'new' developers to tune SQL statements for use in Oracle Financials. Although cost-based optimization has been with us for several years, Oracle Financials was designed to use rule-based optimization and for Financials the 'optimizer_mode' should be set to 'RULE' at the database level. This paper focuses on Oracle's rule-based optimizer - how it works and how an understanding of it can help developers to improve the performance of SQL statements in their programs. Performance tools are described and the paper provides examples and tips that we have gathered from 'trial and error' and while reading about tuning. There are of course many aspects of performance tuning but this paper will only cover the tuning of SQL statements. The process of SQL Tuning can produce dramatic results. A badly tuned SQL report might take 20 hours to run, however by simply changing the code or introducing 'indexes', the same report could be made to run in just minutes! There are plenty of useful books which give detailed accounts of performance tuning. We have used 'Oracle SQL - High-Performance Tuning' by Guy Harrison and 'Oracle Performance Tuning - tips and techniques' by Richard Niemic. There are also a number of well written papers on the subject (see the reference section for a few examples). Nothing in this paper is 'new' or 'revolutionary ', but we have tried to compile some basic principles together to give the developer a 'feel' for the subject. We have also tried to provide some examples from our own work place experiences and these are outlined as 'Case Studies' towards the end of this paper. Every site using Oracle Financials, has its own requirements and although the design is tuned prior to purchasing, data volumes and implementations vary greatly between sites, and developers and DBAs will still need to perform the task of tuning regularly. In addition, each site usually incorporates interfaces between their Oracle Applications and other information systems. These interfaces are coded by developers, and this custom code will often need tuning.

Upload: -

Post on 23-Oct-2014

208 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 1 of 26

PERFORMANCE TUNING FOR FINANCIALSMAKING THE RULE-BASED OPTIMIZER WORK

ASSIST Pty Ltd

INTRODUCTION

This paper has been written with the aim of assisting 'new' developers to tune SQL statements for usein Oracle Financials. Although cost-based optimization has been with us for several years, OracleFinancials was designed to use rule-based optimization and for Financials the 'optimizer_mode' shouldbe set to 'RULE' at the database level.

This paper focuses on Oracle's rule-based optimizer - how it works and how an understanding of it canhelp developers to improve the performance of SQL statements in their programs. Performance toolsare described and the paper provides examples and tips that we have gathered from 'trial and error' andwhile reading about tuning.

There are of course many aspects of performance tuning but this paper will only cover the tuning ofSQL statements. The process of SQL Tuning can produce dramatic results. A badly tuned SQL reportmight take 20 hours to run, however by simply changing the code or introducing 'indexes', the samereport could be made to run in just minutes!

There are plenty of useful books which give detailed accounts of performance tuning. We have used'Oracle SQL - High-Performance Tuning' by Guy Harrison and 'Oracle Performance Tuning - tips andtechniques' by Richard Niemic. There are also a number of well written papers on the subject (see thereference section for a few examples).

Nothing in this paper is 'new' or 'revolutionary', but we have tried to compile some basic principlestogether to give the developer a 'feel' for the subject. We have also tried to provide some examplesfrom our own work place experiences and these are outlined as 'Case Studies' towards the end of thispaper.

Every site using Oracle Financials, has its own requirements and although the design is tuned prior topurchasing, data volumes and implementations vary greatly between sites, and developers and DBAswill still need to perform the task of tuning regularly. In addition, each site usually incorporatesinterfaces between their Oracle Applications and other information systems. These interfaces arecoded by developers, and this custom code will often need tuning.

Page 2: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 2 of 26

WHAT IS AN OPTIMIZER?

SQL is a non-procedural language and as such a SQL statement specifies what "needs to be done" butsays nothing about "how it should be achieved". This role is fulfilled by Oracle software known as an"optimizer". The optimizer determines the most efficient way to access data. Originally there wasonly one mode of optimization available, known as rule-based. A second choice of optimizer mode,known as cost-based, was introduced with Oracle 7.

The essential difference between these two modes is that rule-based optimization uses a fixed set ofranked rules to choose the access path but does not consider any of the data in the database. Cost-based optimization is rather more sophisticated in that it is "aware" of the data in the tables and cantherefore make better-informed decisions based on the volume or arrangement of data. For example,if a table is small enough that the whole table can be read in one I/O operation and an index exists,then a decision not to use the index will be made and a full table scan will be chosen over an indexscan. This is a better decision than could be made by the rule-based optimizer which has noknowledge of table sizes.

Cost-based optimization has the same access options available to it as does rule-based, but will alsoutilise available statistics to assist in the determining the "cost" of each access path. The "cost" isbased upon logical reads, CPU and network calls. Although cost-based optimization may sound like amuch better idea than rule-based, using it can lead to very poor performance unless the database hasbeen tuned to make use of it's capabilities. This involves gathering statistics for use by the cost-basedoptimizer using the ANALYZE command and keeping these statistics up to date as data volumesincrease.

Although all current versions of Oracle Financials (including Release 11) are designed to use rule-based optimization, it is still important for the Financials developer to know about both modes for atleast two reasons. Firstly, it is expected that rule-based optimization will become obsolete in not toodistant future and secondly because some Financials programs do contain "hints" which cause a switchto cost-based optimization. For example, a query in the Account Analysis Report GLRJED.rdfcontains the '/*+ORDERED*/ hint which causes the first table in the FROM clause to become thedriving table.

All hints (except /*+RULE*/) cause a switch to cost-based optimization providing that at least one ofthe tables in the query has been ANALYZED. If a hint is found in a poorly performing program thenthe developer should consider whether ANALYZING the tables may improve performance.

• Some hints to look out are shown below. Note that although these may look a bit like comments,they are not!

SELECT /* +ALL_ROWS */SELECT /*+FIRST_ROWS*/SELECT /*+ORDERED*/

• Sample ANALYZE statementANALYZE TABLE gl.gl_je_lines COMPUTE STATISTICS;

It is normally recommended that for Oracle Financials all hints should be disabled and the rule-basedoptimizer should be used at all times. This is accomplished by setting the parameter'_optimizer_undo_changes' to be TRUE, in the init.ora file.

Page 3: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 3 of 26

HOW THE RULE-BASED OPTIMIZER WORKS

From the developer's point of view, rule-based optimization has an advantage over cost-based in that itis entirely predictable. In other words, for a given SQL statement and set of tables and indexes, thesame access path will always be chosen. This is why an understanding of the access path ranking is soimportant when tuning SQL statements. The following list shows possible table access methods inorder of preference with the most preferable method shown first.

y ACCESS PATH RANKING

Rank Method

1. Single row by ROWID2. Single Row by Cluster Join3. Single row by hash cluster key with unique or primary key4. Single row by unique or primary key5. Cluster Join6. Hash Cluster Join7. Indexed cluster key8. Composite Key9. Single-column Indexes10. Bounded range search on indexed columns11. Unbounded range search on indexed columns12. Sort-merge join13. Max or Min of indexed column14. Order by on indexed column15. Full Table Scan

The basic principle of the rule-based optimizer is to focus on each table in the 'WHERE' clause in turnand rank every possible access path based on the above access-path ranking. Single row by ROWIDhas the lowest rank and the highest ranking access path is Full Table Scan. The access path withlowest rank is selected and the table to which it applies is selected as the "driving table". Theremaining tables are ranked. Again the access path with lowest rank is selected and the join requiredfor it is chosen. This process is repeated, until all tables are joined.

However, the rule-based optimizer knows nothing about the sizes of tables and sometimes the rankingmethod does not produce the best possible execution plan. This problem has been overcome to someextent by cost-based optimization as outlined in the preceding paragraphs.

If an index is found, the rule-based optimizer will automatically classify access via the index aspreferable to a 'full table' scan. However using an index is not always beneficial for performance. Forexample, sometimes, developers put indexes on small tables. If an index is used to access a smalltable two I/O operations will be performed, one on the table the other on the index. It may have beenmore efficient to use a full table scan, which uses only one I/O operation.

Another common mistake is to put an index on a column that has low selectivity; for example acolumn called 'status' that can either by 'Active' or 'Closed'. If 50,000 rows are on a table, and thestatus is 'Active' on 30,000 rows, then a full table scan is preferable because over half the rows areselected and there is no need to access both index blocks and table blocks. Using an index in this caseproduces an I/O performance problem.

Page 4: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 4 of 26

Developers therefore need to review code based on three points:

1) Can performance be improved by creating an index?

2) Can performance be improved by dropping or disabling an index?

3) If all access paths are equal in rank, then can the the smaller table be made to be the driving table?

These points will be discussed in more detail in later sections.

y RETRIEVING DATA

To understand how the rule-based optimizer works, it is important to have a reasonable idea of themethods by which data is retrieved from the database. The optimizer can choose a number of ways toaccess table data. The most common are:

Full Table Scan The whole table is read in memory. Oracle reads all blocks allocatedto the table starting with the first block and continuing until it reachesthe high water mark. This is the highest block that has held data.

ROWID Access Data is accessed directly by using the ROWID (a pseudo-column).This is the fastest access to data.

Index Lookups The index is used to search for the required column values. Oraclewill search the index for the matching key values. The index linksthese matching rows to ROWID.

Hash Key Lookup The data block is determined via a hash function. A hash cluster is atable in which data is physically stored according to the hash value ofa key column.

y JOINING TABLES

The optimizer must decide on the best way to handle table joins in the SQL statement. Joins allowtwo or more tables to be merged, usually based on common key values.

Sort Merge Joins Rule-based optimizer will use this join when an equality joincondition is provided but no index is available. Oracle sorts each tableon the column values used to join two tables and then merges the twostored result sets into one. Sort merge joins are useful in cases wherethere is low selectivity or where an index cannot be used.

Nested Loop Joins Rule-based optimizer will use this join when an index (or hashcluster) exists on at least one of the tables. In nested loop joins, a fulltable scan is done on one table (usually the table with no index, or thesmaller table) and a lookup is performed on the second table that isindexed. Without an index this can be a very inefficient join. Thistype of join provides fast retrieval of the first records back from thejoin.

Full Table Scan Join Rule-based optimizer will use a full table scan join when no indexedjoins exist and an inequality clause is used. One table is used as thedesignated driving table. The second table requires a full table scan tomatch values in the driving table.

Other join options such as hash joins and star joins are not available to the rule-based optimizer.

Page 5: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 5 of 26

y INDEXES

Indexes are Oracle database objects that can be created to enhance performance. There are now severaltypes of indexes including bitmap , hash and partitioned indexes. However the only indexes that therule-based optimizer can use are the standard type known as B-tree indexes. These can be created ona single column or on multiple columns (concatenated indexes). Direct access to the data is achieved,by accessing the ROWID from the Index block.

Indexes should be created on columns or groups of columns which have a high selectivity. An 'InvoiceID' column will contain a unique value for each record and is therefore a good candidate for indexing.A column that will only contain the values 'male', 'female' or 'unknown' would not be suitable for anindex. Generally, if a query returns more than 5% of the rows, it is more efficient to use a full tablescan. This principle is demonstrated in Case Study 1 in which an index with low selectivity was beingused.

The creation of an index does come at some cost when inserting, updating or deleting rows because anadditional operation must occur on the index block as well as on the table. It may even be worthtemporarily removing an index before a large data load.

Rule-based optimization will use an index if it exists, without regard to the size of the table. Asmentioned previously this can often be a disadvantage. Indexes can therefore both enhance anddegrade performance depending on the nature of the data that is being indexed.

When tuning SQL it is vital to know which columns are indexed.

To find a list of Indexes for a tableSELECT index_nameFROM all_indexesWHERE table_name = 'TABLE_NAME';

To find the columns and order of indexes of a given tableSELECT index_name, column_name, column_positionFROM all_ind_columnsWHERE table_name = 'TABLE_NAME';

Page 6: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 6 of 26

TOOLS FOR SQL TUNING

Two of the most useful Oracle tools that can assist the developer in tuning SQL statements are'Explain Plan' and 'SQL Trace'.

y EXPLAIN PLAN

Explain Plan is a tool that can be used to graphically display the execution plan that the optimizer willchoose for a given SQL statement. It can help a developer to find which lines of code to modify toimprove performance. Typical modifications to code include "disabling" an index in favour of a fulltable scan, or "adding" an index to bypass a full table scan.

One of the most useful features of Explain Plan (as compared to SQL Trace) is that the SQL statementdoes not need to be executed. The execution plan can be generated in seconds even though the SQLstatement may take hours to execute.

To use Explain Plan you must first create a table called PLAN_TABLE, the creation script for whichcan be found as $ORACLE_HOME/rdbms/admin/utlxplan.sql. Running Explain Plan inserts recordsinto this table detailing the operations selected by the optimizer. In its most basic form the syntaxrequired to run an Explain Plan on a SELECT statement simply consists of preceding the key-wordSELECT by EXPLAIN PLAN FOR as in:

EXPLAIN PLAN FORSELECT e.ename, d.deptFROM emp e, Dept dWHERE e.deptno = d.deptno/

SQL Plus will respond 'Explained'. To see the explain plan you need to query the PLAN_TABLE. Ahierarchical query such as the one in the script shown below is typically used.

SELECT substr(LPAD(' ',1*(LEVEL-1))||operation,1,32) operation, substr(options,1,16) options, substr(object_name, 1,26) object_name, substr(position,1,3) posFROM plan_tableSTART WITH id = 0CONNECT BY PRIOR id = parent_id;TRUNCATE TABLE plan_table/

For the example shown above this gives the following outputOPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT NESTED LOOPS 1 TABLE ACCESS FULL DEPT 1 TABLE ACCESS BY INDEX ROWID EMP 2 INDEX RANGE SCAN EDEPT 1

The step that the optimizer has chosen to be executed first will be the right-hand most step in the plan.If two steps are equally indented then the upper one is the first to be executed. In the case shownabove the first table access is a full table scan of the dept table.

Page 7: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 7 of 26

y SQL TRACE AND TKPROF

Oracle also provides a tool for tracing SQL statement execution, called SQL Trace. This tool providesall the information provided by the Explain Plan, as well as details of CPU and I/O requirements andnumber of rows processed by each step.

To initiate SQL Trace for a SQL*Plus session issue the commandALTER SESSION SET sql_trace = TRUE.

For PL/SQL usedbms_session.set_sql_trace(TRUE).

When sql_trace is set to TRUE a trace file is generated on the server. The directory where this file iscreated can be revealed using a SELECT statement as follows.

SELECT value FROM v$parameter WHERE name = 'user_dump_dest';

Having found the file the chances are that as a developer you will not be able to read it as onlyapplmgr and the dba group have read permissions. Ask your DBA to make the file readable to the devgroup or better still if security conditions permit ask the DBA to set_TRACE_FILES_PUBLIC=TRUE to allow everyone to read them. The raw trace file is notparticularly informative until you reformat it to give a more meaningful output using 'tkprof' asfollows:

tkprof trace_file output_file explain=username/password sort=(sort options)

One of the most useful features of the tkprof output is that it shows the number of rows retrieved byeach step in the execution plan. Steps processing a large number of rows are prime candidates fortuning.

Case Study 1 shows an example of how we used Trace to help us tune a modified Oracle FinancialsReport.

An easy way to trace a SQL statement without needing to use tkprof, is available in SQL*Plus byissuing the command 'set autotrace on'. Each SQL statement that you execute will then be followed byan execution plan and some statistics on reads, sorts and network traffic. To use this feature you willfirst need to create the PLAN_TABLE.

This paper has only just touched on the power of SQL Trace and the reader wishing to know moreabout this tool may find more information in the books listed in the reference section.

Page 8: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 8 of 26

TUNING TIPS

y TIP 1 UNDERSTAND THE QUERY

Prior to any SQL tuning it is important to understand the query and what it is trying to achieve. It isworthwhile looking at the table structures, table sizes, indexes that exist already, indexes that are beingaccessed and significant columns and distributions. Sometimes an ER (Entity Relationship) Diagramcan help.

Is the design of the SQL statement causing Oracle to do more work than necessary by retrieving morerows than it needs to or forcing sorts that serve no purpose?

Experienced developers, who know the Financials tables well, often become highly skilled in spottingproblems simply by reading the SQL statement, and may never feel the need to use Explain Plan orTrace.

y TIP 2 CREATE AN INDEX TO IMPROVE PERFORMANCE

Creation of an index on a large table can greatly improve performance. Implementors of OracleApplications have a lot of flexibility in designing the customised application via the use of flexfields.Often these flexfields become important data columns that are used regularly to access records. Anexample of such a case is the flexfield segments in the GL_CODE_COMBINATIONS table and itmay be useful to have an index on one or more of the segments.

Developers also implement interfaces to standard tables and interface flexfields become importantcolumns of data that Users will often perform queries against. These interface flexfields are notindexed automatically, and developers sometimes forget to create the index or concatenated index forthem.

For example, the Accounts Receivables AutoInvoice will be slow if the developer does not create anindex on transaction flexfield columns used in queries for Invoice Headers and Invoice Lines. If youuse the interface line attribute columns for recording any interface data then you should create aunique, concatenated index on the following tables:-

RA_CUSTOMER_TRX_LINES_ALLRA_CUSTOMER_TRX_ALLRA_INTERFACE_LINES_ALL

For example, when interface_line_attributes1, 2 and 3 are used for the Autoinvoice a concatenatedindex should be created.

CREATE UNIQUE INDEX index_name ONRA_CUSTOMER_TRX_LINES_ALL (INTERFACE_LINE_ATTRIBUTE1, INTERFACE_LINE_ATTRIBUTE2, INTERFACE_LINE_ATTRIBUTE3);

Every site uses flexfield columns differently and data volumes also vary from site to site, so it isimportant that the developer create indexes where they are useful and DOES NOT create them wherethey will lead to performance degradation.

Page 9: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 9 of 26

y TIP 3 DISABLE AN INDEX TO IMPROVE PERFORMANCE

Sometimes dropping a 'bad' index may have unforseen effects on other parts of the application and it ismore desirable to simply disable the index for a particular SELECT statement. The developer candisable an index by adding 'nothing' to the column. Columns can be modified to disable indexing asfollows:-

Concatenate a blank to the end of a VARCHAR2 field

customer_name || ''

Add zero to a numeric or date fieldcustomer_id + 0 or sysdate + 0

Here is an example from a standard Oracle Financials report. The following lines are from the AgedTrial Balance (4 Buckets) Report (ARXAGE.rdf) :-

where app.gl_date+0 <= to_date(:p_as_of_date,'DD-MON-YYYY')and ps.cash_receipt_id+0 = app.cash_receipt_idand ps.payment_schedule_id+0 < :rp_ps_max_id

If you didn't know why this was done you might think the developer who wrote the code wascompletely crazy to be adding zeros to columns!

We used this technique in Case Studies 1 and 3.

y TIP 4 BE AWARE OF CONCATENATED INDEXES

A concatenated index is simply an index comprising more than one column. These are great becausethe concatenated key is more selective than a single column key index. Columns which are subject tobe queried individually and columns with high selectivity are the best candidates for being the firstcolumn in the index. Oracle Financials makes a lot of use of the concatenated index. For example,GL_CODE_COMBINATIONS will usually have a concatenated index of all its active segments forthe accounting flexfield structure.

Developers can use concatenated indexes to achieve high selectivity, but be aware, that if the leadingpart of the index is not mentioned in the 'WHERE' clause, then the index is not used and this mayresult in a full table scan! Sometimes it is even worth including what looks like a superfluous joinsimply so that the leading column is included in the 'WHERE' clause.

y TIP 5 CHECK FOR MODIFIED INDEX COLUMNS

Modifying a column that is indexed (e.g. by performing a function on it or concatenating it withanother string), will result in the index being disabled. Sometimes developers will inadvertentlydisable an index by having mismatched data types in a join. For example

SELECT p.segment1,sum(revenue_amount)FROM pa_events e,pa_tasks t,pa_projects pWHERE p.segment1 between 1 and 9AND p.project_status_code = 'ACTIVE'AND p.project_id = t.project_idAND t.task_id = e.task_idGROUP BY p.segment1;

Page 10: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 10 of 26

In the table pa_projects, segment1 is a VARCHAR2. In the SQL statement above, Oracleautomatically converts segment1 to 'to_number(segment1)' so that it's datatype is NUMBER matchingthat of 1 and 9. This will disable the index and result in a full table scan. To prevent this fromhappening the '1' and '9' should have been enclosed in quotes so that Oracle would treat them asVARCHAR2.

Other 'unintentional' index modifications to look out for are the use of functions on the index columnsuch as; UPPER, TO_CHAR, TO_DATE and SUBSTR and the coding of an 'IS NULL' on the wherecolumn of the index.

y TIP 6 DON'T USE AN INDEX ON A COLUMN WITH LOW SELECTIVITY

As noted previously, if a query returns more than 5% of the rows, it is usually more efficient to use afull table scan. An index on a column with low selectivity is not a good use for an index. Onemistake that occurs within Oracle Financials is the 'default' of Index set to 'YES' when enteringflexfield segment value. For example, when setting up the accounting flexfield structure. The effect ofthis will be that a single column index is created for each segment. We have seen cases of completelyinappropriate indexing in the chart of accounts on Production databases. In one case a segment wasindexed which had only three or four values in a table of several thousand rows! Developers shoulddrop the index in a case like this or consider replacing it with a concatenated index as discussedpreviously.

Where an index with low selectivity is found, the developer can modify the column to disable theindex. This may be preferable to 'dropping' the index, as the index may well be needed in other SQLcode. TIP 3 discusses how to disable index columns.

Use of this tip is demonstrated in Case Study 1 in which an index with low selectivity was being used.This was causing a large proportion of a table to be read using the index.

y TIP 7 CHOOSE A 'DRIVING' TABLE

The rule-based optimizer will choose as the 'DRIVING' table (first table in the JOIN order) the tablewith the lowest ranking access path.

The rule-based optimizer will tend to choose the join order with the least number of unoptimized joins(eg. those joins that don’t use an index.)

NOTE: A table that is accessed using an outer join cannot be used as a driving table.

If access paths are equal, Oracle will use the last table defined in the FROM clause as the drivingtable.

Where equal ranking occurs, changing the table order in the FROM clause can produce excellentresults. The LAST table in the FROM clause should be the table with the least rows.

For example :-SELECT e.ename, d.deptFROM emp e, dept dWHERE e.deptno = d.deptno

Page 11: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 11 of 26

An index exists on both tables for the deptno. The ranks are equal. Oracle will perform a full tablescan on dept and use an index to find matching records in emp. (See the Explain Plan for this query,discussed previously). Swapping the order of tables will produce a full table scan on emp and an indexmatch on dept. It is best to use the table with the least rows as the driving table. Developers will needto know table sizes of their applications tables to assist in making the correct choice.

See Case Study 2 for an example of how changing the JOIN order helped us to markedly speed up aFinancials program.

NB. If hints have not been suppressed in your database (optimizer_undo_changes set to TRUE) the/*+ORDERED*/ hint can be used to make the FIRST table in the FROM clause be the driving table.

y TIP 8 UNION ALL VS UNION

Developers most commonly use 'UNION' to join two or more result sets with the same number andtypes of columns. A UNION will eliminate any duplicate rows returned from the result sets. Toeliminate the duplicate rows a sort is required.

It is worth considering whether the 'UNION' can be replaced with 'UNION ALL', which is a commandthat is often forgotten by developers. If the query doesn't need to eliminate rows then use 'UNIONALL' as this will avoid an expensive sort.

y TIP 9 USE 'TRUNCATE' INSTEAD OF 'DELETE' FOR CLEARING TEMPORARY TABLES

Don't use 'DELETE' to delete all of the rows from a temporary table as the high water mark is notmoved down. Always use the 'TRUNCATE' command. We have had several interfaces that use atemporary table with SQL*Loader, and replacing 'DELETE' with 'TRUNCATE' improvedperformance.

TRUNCATE has the added advantage of not using up rollback segments (viewed another way thiscould be a disadvantage - you can't rollback a TRUNCATE! - so take care).

y TIP 10 TUNING REPORTS 2.5 WITH TRACE

Release 11 of Oracle Applications allows reports to be traced simply by selecting an option within theapplication but with earlier releases tracing can be achieved as follows.

To activate SQL Trace for your report add the following code to the Before ParameterForm Trigger.IF :p_trace = 'Y' THEN

srw.do_sql('ALTER SESSION SET sql_trace = TRUE');

END IF;

Register the parameter :P_TRACE in the Concurrent Program definition with value set "Yes_No'.This can be used to turn SQL-trace on or off when running the report. Some standard Financialsreports already have code similar to this.

Case Study 1 shows an example of how we used Trace to help us tune a modified Oracle FinancialsReport.

Page 12: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 12 of 26

y TIP 11 SET TIMING ON

A useful and often overlooked tool for comparing the performance of SQL statements is the SQL Plus'timing' feature. Issuing the SQL Plus command 'SET timing ON' will allow you to see how long SQLstatements take to execute without you having to sit in front of the computer with a stopwatch!

NB: Be careful not to be fooled into thinking that you have speeded up a query if it executes faster ona second run. It may simply be that the data has been cached in memory by the first run!

y TIP 12 GETTING THE DYNAMIC SQL FROM FORMS 4.5

A problem may occur in a form, where data is taking a long time to be retrieved. The Developer willneed to access the SQL code that does the retrieval, before an analysis can be made on performance. Atip to retrieving the dynamic SQL, provided by Andy Tremayne (Oracle UK) which we have founduseful is the following :

1. Put the Form in Query Mode (Query Enter)2. Enter #XXX in any 'database' field. This will append AND <field_name> XXX to the

WHERE clause3. Execute the Query - This will create an error (ORA-00920 'invalid relational operator')4. Acknowledge the error, cancel the query, and select HELP/VIEW Database error5. Review the database error which will show the query being executed at the time the form

'Crashed'

The select statement will list all form fields being retrieved from the database. You should then be ableto 'copy' and 'paste' the SQL and test the code in SQL*Plus. You then will be able to run your ExplainPlan or SQL Trace on the query, and tune the code.

y TIP 13 STOP USERS DOING THOSE AWFUL QUERIES

FIND windows in Oracle Applications cause performance problems when the USER does not enter atleast some criteria to use in the SQL query. If no data is entered then the SQL is forced to do full tablescans and this may result in joins of huge tables that can cripple a system. An excellent tip has beenprovided by Brad Goodwin (Oracle) in modifying the CUSTOM library to include a customised eventfor the 'WHEN-BUTTON_PRESSED' trigger on the Find button. This can be used to prevent thequery from being run unless the user has entered criteria to limit the search.

The custom library doesn't get the 'WHEN-BUTTON_PRESSED' event, so the FORM will need to bemodified to pass a custom 'FIND' event from the 'WHEN-BUTTON_PRESSED' trigger. The code toput in CUSTOM.pll is as follows:-

IF (event_name = 'CUSTOM_FIND') THEN--Has the user entered criteria into the fields? Query_fields := NAME_IN('Block.field1') || NAME_IN('Block.field2') ||

NAME_IN('Block.field3') ||NAME_IN('Block.field4') ||NAME_IN('Block.field5') ;

--If not then INFORM users of errorIF query_fields IS NULL THENFnd_message.set_string('To avoid a serious performance degradation, you MUST supply atleast one criterion before querying.);--Disable QueryCOPY('FALSE','parameter.g_query_find'); END IF; END IF;END Event;

Page 13: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 13 of 26

y TIP 14 FINDING THE PROBLEM QUERIES IN YOUR DATABASE

If you are in a position where performance is poor and you suspect that poorly written SQL statementsare the problem but you don't know which statements are the culprit, you can find the worst offendersby querying the v$sqlarea view. The following queries will show which SQL statements areresponsible for the most disk reads:

SELECT disk_reads, sql_textFROM v$sqlareaWHERE disk_reads > 100000ORDER by disk_reads/

and memory reads:SELECT buffer_gets, sql_textFROM v$sqlareaWHERE buffer_gets > 100000ORDER by buffer_gets/

The number '100000' is just a guide and may need to made larger or smaller. There are several otherv$ dynamic views relating to tuning and these can be useful for the DBA but are of less interest to thedeveloper tuning SQL.

And last but not least…..

y TIP 15 KNOW YOUR DATA

Every Site that has Oracle Financials has different data volumes and different ways of accessing data.SQL code that performs well at one site may perform dreadfully at another. Know your data, and youwill be able to determine what works best for your own environment!

Page 14: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 14 of 26

CONCLUSION

This has been a brief introduction to the world of the rule-based optimizer and SQL tuning. We haveattempted to cover what we, as developers, have found to be the most useful points needed to getstarted with SQL tuning in an Oracle Financials environment.

Understanding rule-based optimization and the choices made by Oracle in the execution of a SQLstatement is the first step to any effective SQL tuning. Armed with this knowledge the developer canchange performance dramatically! Simple changes such as; creation of an index, identifying indexesthat are inadvertently disabled, changing the table order or dropping an index are just a few techniquesthat we have used successfully in our tuning endeavours.

For those wishing to pursue this topic further there are many excellent reference books and papers onthe subject and we would also encourage people to experiment using SQL Plus to try out the differenttuning techniques.

Page 15: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 15 of 26

CASE STUDY 1: AR AGED TRIAL BALANCE 7 BUCKETSBY RESPONSIBILITY CENTRE

A client required a modified form of the Aged Trial Balance report which could be run for a range ofresponsibility centres. The standard Oracle AR report ARXAGF.rdf was modified to add thefollowing lines to two select statementsAND c.segment3 >= :p_rc_lowAND c.segment3 <= :p_rc_high

...and two new parameters, RC low and RC high were registered in the AOL.

This addition gave the desired functionality but caused the execution time to increase from 1 minute18 seconds to 2 hours 20 minutes!

What caused this loss in performance? To investigate the problem we used SQL Trace to produce anexecution plan. We added code to the BeforeParameterForm trigger to switch on SQL Trace asdescribed previously. The trace file contains execution plans for the select statements in the reports.

We generated Trace files for unmodified and modified programs then compared the execution plans.Here they are for one of the select statements in the report…

Page 16: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 16 of 26

y ARXAGF.RDF BEFORE MODIFICATION (EXECUTION TIME 1 MINUTE 18 SECONDS)Rows Execution Plan------- --------------------------------------------------- 0 SELECT STATEMENT GOAL: RULE 1 SORT (ORDER BY) 1 UNION-ALL 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 549 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 550 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE) 544 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 549 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_TYPES_ALL' 0 INDEX (UNIQUE SCAN) OF 'RA_CUST_TRX_TYPES_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_LINE_GL_DIST_ALL' 0 INDEX (RANGE SCAN) OF 'RA_CUST_TRX_LINE_GL_DIST_N6' (NON-UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 0 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE)

1 SORT (GROUP BY) 1 NESTED LOOPS 4 NESTED LOOPS 549 FILTER 544 NESTED LOOPS (OUTER) 549 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 550 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE) 544 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 549 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE)

4 TABLE ACCESS (BY ROWID) OF 'AR_RECEIVABLE_APPLICATIONS_ALL' 8 INDEX (RANGE SCAN) OF 'AR_RECEIVABLE_APPLICATIONS_N1' (NON-UNIQUE) 4 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 4 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE) 0 FILTER 0 FILTER 0 NESTED LOOPS (OUTER) 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 0 TABLE ACCESS (FULL) OF 'AR_CASH_RECEIPT_HISTORY_ALL' 0 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 0 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_CASH_RECEIPTS_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_CASH_RECEIPTS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_PAYMENT_SCHEDULES_U2' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 0 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE)

Page 17: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 17 of 26

y AFTER MODIFICATION BUT BEFORE TUNING (EXECUTION TIME 2 HOURS 20 MINUTES)Rows Execution Plan------- --------------------------------------------------- 0 SELECT STATEMENT GOAL: RULE 0 SORT (ORDER BY) 0 UNION-ALL 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS2352465 NESTED LOOPS 4409 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 4410 INDEX (RANGE SCAN) OF 'GL_CODE_COMBINATIONS_N3' (NON-UNIQUE)2352465 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL'2356750 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE)2331040 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS'2352465 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_TYPES_ALL' 0 INDEX (UNIQUE SCAN) OF 'RA_CUST_TRX_TYPES_U1' (UNIQUE)

0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_LINE_GL_DIST_ALL' 0 INDEX (RANGE SCAN) OF 'RA_CUST_TRX_LINE_GL_DIST_N6' (NON-UNIQUE) 0 SORT (GROUP BY) 0 NESTED LOOPS2352465 FILTER2331040 NESTED LOOPS (OUTER)2352465 NESTED LOOPS 4409 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 4410 INDEX (RANGE SCAN) OF 'GL_CODE_COMBINATIONS_N3' (NON-UNIQUE)2352465 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL'2356750 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE)2331040 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS'2352465 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE) 17140 TABLE ACCESS (BY ROWID) OF 'AR_RECEIVABLE_APPLICATIONS_ALL' 34280 INDEX (RANGE SCAN) OF 'AR_RECEIVABLE_APPLICATIONS_N1' (NON-UNIQUE) 0 FILTER 0 FILTER 0 NESTED LOOPS (OUTER) 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 0 TABLE ACCESS (FULL) OF 'AR_CASH_RECEIPT_HISTORY_ALL' 0 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 0 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_CASH_RECEIPTS_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_CASH_RECEIPTS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_PAYMENT_SCHEDULES_U2' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS'

0 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE)

Page 18: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 18 of 26

Comparing the execution plans for the original report ARXAGF.rdf and the modified reportARCAGF.rdf shows that the new report (which selects by reponsibility centre) is using an index onresponsibility centre (glcc.segment3). This index has low selectivity e.g. picking one responsibilitycentre might return over 10% of the rows, which is not an efficient use of the index.

Disabling the index by convertingAND c.segment3 >= :p_rc_low

AND c.segment3 <= :p_rc_high

toAND c.segment3||'' >= :p_rc_low

AND c.segment3||'' <= :p_rc_high

caused the execution time to be reduced from 2 hours 20 minutes to 1 minute 6 seconds! Thefollowing diagram shows the Explain Plan after tuning. Note that it has reverted to something verylike that of the unmodified report.

Page 19: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 19 of 26

y AFTER MODIFICATION AND TUNING (EXECUTION TIME 1 MINUTE 6 SECONDS).Rows Execution Plan------- --------------------------------------------------- 0 SELECT STATEMENT GOAL: RULE 0 SORT (ORDER BY) 0 UNION-ALL 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 549 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 550 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE) 544 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 549 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_TYPES_ALL' 0 INDEX (UNIQUE SCAN) OF 'RA_CUST_TRX_TYPES_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUST_TRX_LINE_GL_DIST_ALL' 0 INDEX (RANGE SCAN) OF 'RA_CUST_TRX_LINE_GL_DIST_N6' (NON-UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 0 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE)

0 SORT (GROUP BY) 0 NESTED LOOPS 4 NESTED LOOPS 549 FILTER 544 NESTED LOOPS (OUTER) 549 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 550 INDEX (RANGE SCAN) OF 'AR_PAYMENT_SCHEDULES_N9' (NON-UNIQUE) 544 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 549 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE)

4 TABLE ACCESS (BY ROWID) OF 'AR_RECEIVABLE_APPLICATIONS_ALL' 8 INDEX (RANGE SCAN) OF 'AR_RECEIVABLE_APPLICATIONS_N1' (NON-UNIQUE) 4 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 4 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE) 0 FILTER 0 FILTER 0 NESTED LOOPS (OUTER) 0 NESTED LOOPS 0 NESTED LOOPS 0 NESTED LOOPS 0 TABLE ACCESS (FULL) OF 'AR_CASH_RECEIPT_HISTORY_ALL' 0 TABLE ACCESS (BY ROWID) OF 'GL_CODE_COMBINATIONS' 0 INDEX (UNIQUE SCAN) OF 'GL_CODE_COMBINATIONS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_CASH_RECEIPTS_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_CASH_RECEIPTS_U1' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'AR_PAYMENT_SCHEDULES_ALL' 0 INDEX (UNIQUE SCAN) OF 'AR_PAYMENT_SCHEDULES_U2' (UNIQUE) 0 TABLE ACCESS (BY ROWID) OF 'RA_CUSTOMERS' 0 INDEX (UNIQUE SCAN) OF 'RA_CUSTOMERS_U1' (UNIQUE)

Page 20: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 20 of 26

CASE STUDY 2: A GL JOURNAL REPORT

A custom report was taking 10 minutes to run which was longer than expected.

The script was:

SELECT to_char(sysdate,'DD-MON-YY') Today, js.user_je_source_name Source, headers.period_name Period_name, batch.name Batch, cc.segment1 || '.' || cc.segment2 Entity, sum(lines.entered_dr) Entered_DR, sum(lines.entered_cr) Entered_CRFROM GL.GL_JE_HEADERS headers, GL.GL_JE_SOURCES js, GL.GL_JE_BATCHES batch, GL.GL_CODE_COMBINATIONS cc, GL.GL_JE_CATEGORIES jc, GL.GL_JE_LINES linesWHERE lines.je_header_id = headers.je_header_idAND headers.status = 'P'AND headers.je_source = js.je_source_nameAND headers.je_category = jc.je_category_nameAND headers.set_of_books_id = 2AND lines.code_combination_id = cc.code_combination_idAND headers.posted_date is not NULLAND headers.attribute5 is NULLAND jc.user_je_category_name not like '%SPLIT'AND batch.je_batch_id = headers.je_batch_idGROUP BY js.user_je_source_name, headers.period_name, batch.name, cc.segment1 || '.' || cc.segment2/

We ran an explain plan which gave the following…

Page 21: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 21 of 26

OPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT SORT GROUP BY 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 TABLE ACCESS FULL GL_JE_LINES 1 TABLE ACCESS BY ROWID GL_CODE_COMBINATIONS 2 INDEX UNIQUE SCAN GL_CODE_COMBINATIONS_U1 1 TABLE ACCESS BY ROWID GL_JE_HEADERS 2 INDEX UNIQUE SCAN GL_JE_HEADERS_U1 1 TABLE ACCESS BY ROWID GL_JE_CATEGORIES 2 INDEX UNIQUE SCAN GL_JE_CATEGORIES_U1 1 TABLE ACCESS BY ROWID GL_JE_BATCHES 2 INDEX UNIQUE SCAN GL_JE_BATCHES_U1 1 TABLE ACCESS BY ROWID GL_JE_SOURCES 2 INDEX UNIQUE SCAN GL_JE_SOURCES_U1 1

In the above execution plan, the fact that the lines table (gl_je_lines) is indented further to the rightthan the headers table (gl_je_headers) shows that it is being accessed first. Not only is this badbecause there are many lines to each header but also lines are even being read from header recordswhich should have been eliminated by other where conditions (e.g. 'headers.status = 'P').

In this version of the script the lines table is the last table in the FROM clause and the HEADERStable is the first table in the FROM clause. If all else is equal the rule-based optimizer will choose thelast table in the FROM clause as the driving table. Suspecting that the position of the lines table in thefrom clause was responsible for it being accessed first we tried swapping the positions of the headersand lines tables in the FROM clause. The new script (with header table at the bottom of the FROMclause) gave the following execution plan.

OPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT SORT GROUP BY 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 TABLE ACCESS FULL GL_JE_HEADERS 1 TABLE ACCESS BY ROWID GL_JE_CATEGORIES 2 INDEX UNIQUE SCAN GL_JE_CATEGORIES_U1 1 TABLE ACCESS BY ROWID GL_JE_BATCHES 2 INDEX UNIQUE SCAN GL_JE_BATCHES_U1 1 TABLE ACCESS BY ROWID GL_JE_SOURCES 2 INDEX UNIQUE SCAN GL_JE_SOURCES_U1 1 TABLE ACCESS BY ROWID GL_JE_LINES 2 INDEX RANGE SCAN GL_JE_LINES_U1 1 TABLE ACCESS BY ROWID GL_CODE_COMBINATIONS 2 INDEX UNIQUE SCAN GL_CODE_COMBINATIONS_U1 1

Note that the headers table is now the driving table. The effect of this change on performance wasdramatic. The execution time dropped from 10 minutes to 1 second!

Page 22: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 22 of 26

CASE STUDY 3: CUSTOM ASSET ADDITION REPORT(A CASE OF THE UNEXPECTED)

A client of ours had a custom "Asset Addition Report" which took over 3 hours to run. We suspectedthat an index FA_TRANSACTION_HEADERS_N2 was being used inefficiently because the columnit indexes (transaction_type_code) has low selectivity. Dropping this index caused the execution timeto drop from 3 hours 20 minutes to 1 minute.

The same effect was achieved without dropping the index by concatentating ||'' to the two occurencesof the indexed column transaction_type_code.

At this stage we were happy to conclude that the performance problem had been a result of theinefficient use of an index with low selectivity.

Later we did an experiment to investigate the effect of disabling the index on just one of the twooccurrences of transaction_type_code.

AND THADD.Transaction_Type_Code = 'ADDITION'AND THDIS.Transaction_Type_Code(+) = 'TRANSFER IN'.

To our surprise we found that appending ||'' to the line;AND THADD.Transaction_Type_Code = 'ADDITION'

had no performance improving effect at all but appending ||'' to the line;AND THDIS.Transaction_Type_Code(+) = 'TRANSFER IN'.

was just as effective as dropping the index.

We then changed the code of the original script so as to remove the outer join without disabling theindex. The report then ran in 1 minute. Further investigation of the code showed that the outer joinserved no functional purpose so it could be permanently removed.

Simply removing an outer join caused a dramatic change in the execution plan and increasedperformance 200-fold. This example demonstrates not only that great care must be taken with outerjoins but also that there may be more than one way improve the performance of an SQL statement

Following are the Execution Plans…..

Page 23: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 23 of 26

y BEFORE ANY TUNING (EXECUTION TIME 3 HOURS 20 MINUTES)

OPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT SORT ORDER BY 1 NESTED LOOPS 1 TABLE ACCESS FULL FA_DEPRN_PERIODS 2 NESTED LOOPS 1 TABLE ACCESS FULL FA_DEPRN_PERIODS 2 NESTED LOOPS 1 INDEX RANGE SCAN FA_CATEGORY_BOOKS_U1 2 NESTED LOOPS 1 TABLE ACCESS BY ROWID FA_CATEGORIES 2 INDEX UNIQUE SCAN FA_CATEGORIES_U1 1 NESTED LOOPS 1 TABLE ACCESS BY ROWID FA_ASSET_HISTORY 2 INDEX RANGE SCAN FA_ASSET_HISTORY_N2 1 NESTED LOOPS 1 TABLE ACCESS BY ROWID FA_DEPRN_SUMMARY 2 INDEX RANGE SCAN FA_DEPRN_SUMMARY_U1 1 NESTED LOOPS OUTER 1 TABLE ACCESS BY ROWID PO_VENDORS 2 INDEX UNIQUE SCAN PO_VENDORS_U1 1 NESTED LOOPS 1 TABLE ACCESS BY ROWID FA_ASSET_INVOICES 2 INDEX RANGE SCAN FA_ASSET_INVOICES_N2 1 FILTER 1 NESTED LOOPS OUTER 1 TABLE ACCESS BY ROWID GL_CODE_COMBINATIONS 2 INDEX UNIQUE SCAN GL_CODE_COMBINATIONS_U1 1 FILTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 TABLE ACCESS FULL FA_DEPRN_PERIODS 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N2 1 TABLE ACCESS BY ROWID FA_ADDITIONS 2 INDEX UNIQUE SCAN FA_ADDITIONS_U1 1 TABLE ACCESS BY ROWID FA_BOOKS 2 INDEX UNIQUE SCAN FA_BOOKS_U1 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N2 1 TABLE ACCESS BY ROWID FA_DISTRIBUTION_HISTORY 2 INDEX RANGE SCAN FA_DISTRIBUTION_HISTORY_N1 1 TABLE ACCESS BY ROWID FA_LOCATIONS 2 INDEX UNIQUE SCAN FA_LOCATIONS_U1 1

Page 24: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 24 of 26

y INDEX DROPPED (EXECUTION TIME 1 MINUTE)

OPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT SORT ORDER BY 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 FILTER 1 NESTED LOOPS OUTER 1 FILTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS OUTER 1 TABLE ACCESS FULL FA_ASSET_INVOICES 1 TABLE ACCESS BY ROWID PO_VENDORS 2 INDEX UNIQUE SCAN PO_VENDORS_U1 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N1 1 TABLE ACCESS BY ROWID FA_ADDITIONS 2 INDEX UNIQUE SCAN FA_ADDITIONS_U1 1 TABLE ACCESS BY ROWID FA_BOOKS 2 INDEX UNIQUE SCAN FA_BOOKS_U1 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N1 1 TABLE ACCESS BY ROWID FA_DISTRIBUTION_HISTORY 2 INDEX RANGE SCAN FA_DISTRIBUTION_HISTORY_N1 1 TABLE ACCESS BY ROWID FA_LOCATIONS 2 INDEX UNIQUE SCAN FA_LOCATIONS_U1 1 TABLE ACCESS BY ROWID GL_CODE_COMBINATIONS 2 INDEX UNIQUE SCAN GL_CODE_COMBINATIONS_U1 1 TABLE ACCESS BY ROWID FA_DEPRN_SUMMARY 2 INDEX RANGE SCAN FA_DEPRN_SUMMARY_U1 1 TABLE ACCESS BY ROWID FA_ASSET_HISTORY 2 INDEX RANGE SCAN FA_ASSET_HISTORY_N2 1 TABLE ACCESS BY ROWID FA_CATEGORIES 2 INDEX UNIQUE SCAN FA_CATEGORIES_U1 1 INDEX RANGE SCAN FA_CATEGORY_BOOKS_U1 2 TABLE ACCESS FULL FA_DEPRN_PERIODS 2 TABLE ACCESS FULL FA_DEPRN_PERIODS 2 TABLE ACCESS FULL FA_DEPRN_PERIODS 2

Page 25: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 25 of 26

y OUTER JOIN REMOVED (EXECUTION TIME 1 MINUTE)

OPERATION OPTIONS OBJECT_NAME POS-------------------------------- ---------------- -------------------------- ---SELECT STATEMENT SORT ORDER BY 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 FILTER 1 NESTED LOOPS OUTER 1 FILTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 FILTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS OUTER 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 NESTED LOOPS 1 TABLE ACCESS FULL FA_DEPRN_PERIODS 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N2 1 TABLE ACCESS BY ROWID FA_ADDITIONS 2 INDEX UNIQUE SCAN FA_ADDITIONS_U1 1 TABLE ACCESS BY ROWID FA_BOOKS 2 INDEX UNIQUE SCAN FA_BOOKS_U1 1 TABLE ACCESS BY ROWID FA_ASSET_INVOICES 2 INDEX RANGE SCAN FA_ASSET_INVOICES_N2 1 TABLE ACCESS BY ROWID PO_VENDORS 2 INDEX UNIQUE SCAN PO_VENDORS_U1 1 TABLE ACCESS BY ROWID FA_TRANSACTION_HEADERS 2 INDEX RANGE SCAN FA_TRANSACTION_HEADERS_N1 1 TABLE ACCESS BY ROWID FA_DISTRIBUTION_HISTORY 2 INDEX RANGE SCAN FA_DISTRIBUTION_HISTORY_N1 1 TABLE ACCESS BY ROWID FA_LOCATIONS 2 INDEX UNIQUE SCAN FA_LOCATIONS_U1 1 TABLE ACCESS BY ROWID GL_CODE_COMBINATIONS 2 INDEX UNIQUE SCAN GL_CODE_COMBINATIONS_U1 1 TABLE ACCESS BY ROWID FA_DEPRN_SUMMARY 2 INDEX RANGE SCAN FA_DEPRN_SUMMARY_U1 1 TABLE ACCESS BY ROWID FA_ASSET_HISTORY 2 INDEX RANGE SCAN FA_ASSET_HISTORY_N2 1 TABLE ACCESS BY ROWID FA_CATEGORIES 2 INDEX UNIQUE SCAN FA_CATEGORIES_U1 1 INDEX RANGE SCAN FA_CATEGORY_BOOKS_U1 2 TABLE ACCESS FULL FA_DEPRN_PERIODS 2

TABLE ACCESS FULL FA_DEPRN_PERIODS 2

Page 26: Performance Tuning

File: Performance_Tuning.doc © ASSIST Pty Ltd Date: September 1999 Page: 26 of 26

ACKNOWLEDGMENTS

We would like to thank Simon Haddon for his helpful discussions and work on Case Study 3, andPenny Cookson (Sage) for her 'Application Tuning Workshop'.

y REFERENCES

Foote, Richard, 'A-Z of Oracle Database Tuning' OUG, Canberra, 1999

Goodwin, Brad, 'Altering Oracle Forms Functionality without altering Oracle Forms Code', OAUG,Spring 99

Harrison, Guy, 'Oracle SQL High-Performance Tuning', Prentice Hall PTR,New Jersey, 1998

Lockhart, Janette, 'Performance Tuning for the Oracle Developer' OUAG Spring 98

Niemic, Richard, 'Oracle Performance Tuning - tips and techniques' Osborne/McGraw-Hill, Berkley,1999

Saksena, Virag, 'Identifying and Optimizing the SQL Code for concurrent manager Batch jobs',OAUG 1996

Scheurich, Sheilah, 'Applications/Database Tuning - A Practical Business Approach', OUAG Fall 98

Tremayne, Andy, 'A Holistic Approach to Performance Tuning Oracle Application Systems ', OAUGEurope(Barcelona) 1999