Monday, September 26, 2016

Oracle PL/SQL Performance Tips


1)          Avoid Usage of  “Like”
The LIKE-clause can ignore indexes, causing queries to run forever while doing full table scans.
Generally, search arguments in the WHERE clause such as "IS NULL", "<>", "!=", "!>", "!<", "NOT", "NOT EXISTS", "NOT IN", "NOT LIKE", and "LIKE '%500'" prevents Oracle from using an index to perform the search (however, not always).

If you use LIKE in your WHERE clause, try to specify one or more leading characters if at all possible. For example, use LIKE 'm%' and not LIKE '%m'. If you specify a leading character, Oracle has a better chance of being able to use an index to perform the query - this will increase performance and reduce the load on the database server.

2)          Use “Exists” and “Not Exists”  instead of  “ in” and “not in
When coding a SQL statement with tables in master-detail relationships, it's common to have to decide whether to write the query using the WHERE EXISTS (. . .) clause or the WHERE value IN (. . .) clause. You may resist using WHERE EXISTS because it has the awkward syntax of returning a value, which you always ignore.

However, there's a difference when using rule-based optimization. You can determine the performance of a rule-based query by understanding which table is the driving table and how many rows each part returns.

When you write a query using the IN clause, you're telling the rule-based optimizer that you want the innerquery to drive the outer query (think: IN = inside to outside). For example, to query the 14-row EMP table for the direct reports to the employee KING, you could write the following:
SELECT ename
  FROM emp e
WHERE mgr IN (SELECT empno
                              FROM emp
                            WHERE ename = 'KING'
                           );

You can write the same query using EXISTS bymoving the outer query column to a subquery condition, likethis:
  SELECT ename
   FROM emp e
 WHERE EXISTS ( SELECT ‘Y’
                               FROM emp
                             WHERE e.mgr = empno
                                  AND ename = 'KING'
                             );

When you write EXISTS in a where clause, you’re telling the optimizer that you want the outer query to be run first, using each value to fetch a value from the inner query(think: EXISTS = outside to inside).
To determine which clause offers better performance in rule-based optimization, consider how many rows the inner query will return in comparison to the outer query. In many cases, EXISTS is better because it requires you to specify a join condition, which can invoke an INDEX scan. However, IN is often better if the results of the subquery are very small. You usually want to run the query that returns the smaller set of results first.

3)          Use “bulk collect“ if data fetched is huge
 When filling a PLSQL collection you can either do this one row at a time (the slow way) using a cursor FOR LOOP or you can fill it one hit by using BULK COLLECT. By BULCOLLECT SQL statement will be executed only once by the Oracle database instead of multiple times.

The BULK COLLECT clause can be used with the SELECT INTO and FETCH statements and the RETURNING clause of DELETE, INSERT and UPDATE statements.

Example:
DECLARE

    TYPE employee_tab_typ IS TABLE OF  employee%ROWTYPE;
    TYPE emp_id_tab_typ      IS TABLE OF employee.emp_id%TYPE;
   
    CURSOR all_employees
    IS
       SELECT *
        FROM employee;

    TYPE all_emp_tab_typ IS TABLE OF all_employee%ROWTYPE;

    employee_tab employee_tab_typ;
    emp_id_tab      emp_id_tab_typ;
    all_emps            all_emp_tab_typ;

BEGIN

    SELECT *
     FROM employee
     BULK COLLECT INTO employee_tab;

    OPEN all_employees;
    FETCH all_employees INTO all_emps;

UPDATE employees
         SET sal=sal*1.1
      WHERE role='DEVELOPER'
    RETURNING emp_id INTO emp_id_tab;
   
    CLOSE all_employees;

END;

DML – use Dynamic SQL
Tuning Dynamic SQL with EXECUTE IMMEDIATE Statement and Cursor Variables
Some programs (a general-purpose report writer for example) must build and process a variety of SQL statements, where the exact text of the statement is unknown until run time. Such statements probably change from execution to execution. They are called dynamic SQL statements.

Formerly, to execute dynamic SQL statements, you had to use the supplied package DBMS_SQL. Now, within PL/SQL, you can execute any kind of dynamic SQL statement using an interface called native dynamic SQL. The main PL/SQL features involved are the EXECUTE IMMEDIATE statement and cursor variables (also known as REF CURSORs).

Native dynamic SQL code is more compact and much faster than calling the DBMS_SQL package.

4)          No Copy
Tuning PL/SQL Subprogram Calls with NOCOPY Hint

By default, OUT and IN OUT parameters are passed by value. The values of any IN OUT parameters are copied before the subprogram is executed. During subprogram execution, temporary variables hold the output parameter values. If the subprogram exits normally, these values are copied to the actual parameters. If the subprogram exits with an unhandled exception, the original parameters are unchanged.

When the parameters represent large data structures such as collections, records, and instances of object types, this copying slows down execution and uses up memory. In particular, this overhead applies to each call to an object method: temporary copies are made of all the attributes, so that any changes made by the method are only applied if the method exits normally.

To avoid this overhead, you can specify the NOCOPY hint, which allows the PL/SQL compiler to pass OUT and IN OUT parameters by reference. If the subprogram exits normally, the action is the same as normal. If the subprogram exits early with an exception, the values of OUT and IN OUT parameters (or object attributes) might still change. To use this technique, ensure that the subprogram handles all exceptions.

5)          Usage of  hints
Use hints to force the optimizer to use a specific chosen execution plan.
Hints are suggestions that you give to the optimizer for optimizing a SQL statement

Use hints to specify
                                 The optimization approach for a SQL statement
                                 The goal of the cost-based approach for a SQL statement
                                 The access path for a table accessed by the statement
                                 The join order for a join statement
                                 A join operation in a join statement

6)          Create indexes  where ever required
An index is an optional structure, associated with a table that can sometimes speed data access. By creating an index on one or more columns of a table, you gain the ability in some cases to retrieve a small set of randomly distributed rows from the table. Indexes are one of many means of reducing disk I/O.
             It avoids full table scan
             Index is an easier way to access the data.
             Create indexes on fields that are queried on most frequently.
             Indexing speeds up select.

If the database has lot of DML operations do not have more than 2 (max 3) for a table
                     While updating an indexed column, we delete the original value of the index and create a new one as the column which is being indexed is being changed. This will have two I/O as one for the data block and another for the index block.
                     Solution to this is to drop the index before updating and recreate it after updating is complete.
                     To rebuild the index,
      -  Alter index index_name rebuild

Create Indexes on fields which have a high Selectivity factor (around 0.7)

Selectivity factor  =  No. of distinct values for a field / Total rows in the table

7)          Tkprof, explain  plan, cost of sqls
Use the EXPLAIN PLAN statement to determine the execution plan Oracle Database follows to execute a specified SQL statement. This statement inserts a row describing each step of the execution plan into a specified table PLAN_TABLE. You can also issue the EXPLAIN PLAN statement as part of the SQL trace facility.

TKPROF is a program that you invoke at the operating system command prompt in order to reformat the trace file into a format that is much easier to comprehend. Each SQL statement is displayed in the report, along with counts of how many times it was parsed, executed, and fetched. CPU time, elapsed time, logical reads, physical reads, and rows processed are also reported, along with information about recursion level and misses in the library cache. TKPROF can also optionally include the execution plan for each SQL statement in the report, along with counts of how many rows were processed at each step of the execution plan.

EXPLAIN PLAN and TKPROF allow you to proactively tune an application while it is in development. It is relatively easy to enable SQL trace, run an application in a test environment, run TKPROF on the trace file, and review the output to determine if application or schema changes are called for. EXPLAIN PLAN is handy for evaluating individual SQL statements.

8)          Follow order to map joins
Suppose if there are three tables in a query first complete all the joins between two tables and then add join conditions with the third table.

9)           When custom logic is repetitive, use stored procedure/function.

10)      Avoiding Memory Overhead in PL/SQL Code:

Declare VARCHAR2 Variables of 4000 or More Characters
You might need to allocate large VARCHAR2 variables when you are not sure how big an expression result will be. You can conserve memory by declaring VARCHAR2 variables with large sizes, such as 32000, rather than estimating just a little on the high side, such as by specifying 256 or 1000. PL/SQL has an optimization that makes it easy to avoid overflow problems and still conserve memory. Specify a size of more than 4000 characters for the VARCHAR2 variable; PL/SQL waits until you assign the variable, then only allocates as much storage as needed.

11)      Make loops as efficient as possible
 Because PL/SQL applications are often built around loops, it is important to optimize both the loop itself and the code inside the loop:

             To issue a series of DML statements, replace loop constructs with FORALL statements.
             To loop through a result set and store the values, use the BULK COLLECT clause on the query to bring the query results into memory in one operation

12)      Use lookups instead of hardcoding the values in the code.

Programming Standards for PLSQL objects

PL/SQL Objects

Objects such as Libraries, Procedures, Functions and Packages will be owned by APPS

Indentation – Suggestion of 2 characters for all new programs.  Follow through with the written style on old programs.  Usage of TABS are discouraged because many editors can be set to interpret TAB widths differently and thus indentation and vertical alignment can vary depending on the editor used to the view code. The main point being, make the logic readable with efficient use of horizontal space.

IF Statements - IF, THEN, ELSE and ENDIF must align vertically. Furthermore, nested IF statements should be indented and it’s corresponding THEN, ELSE and ENDIF segments must align vertically.

Looping - LOOP and END LOOP statements must align vertically. All statements contained within the loop must be indented. The first line of the loop must be a comment statement describing the purpose of the loop.

Branching - GO-TO statements are not allowed, with the exception of error handling. Instead, the programmer should use externally called sub-procedures with passing arguments, as required.

Line Continuation - Program statements require more than one line for various reasons. Generally a line of code must not exceed 80 characters, including preceding special characters and spaces. The rules’ governing the structure of multi-line statements follows.

Procedure calls argument list - one argument per line with the second and subsequent lines indented the same number of spaces
DDL, DML statement - one column per line with the second and subsequent lines indented the same number of spaces
Other multi-line statements - second and subsequent lines indented the same number of spaces

·         All reserved words, key Oracle words, table aliases to be capitalized and all others (column names, column aliases etc.) should be in lower case.
Examples: -
1. Statements: SELECT, UPDATE, INSERT, ALTER, CREATE, COMMIT, ROLLBACK
2. Clauses: INTO, FROM, WHERE, GROUP BY, ORDER BY, SET
3. Functions: TO_CHAR, TO_DATE, DECODE, NULL, NVL, RTRIM
4. Operators: AND, OR, BETWEEN, EXISTS, IN, NOT
5. Table Aliases: RCT

·         Comma (,) separating parameters, columns or tables should appear at the beginning of lines and not at the end of the lines.
·         Source code indentation is essential.
·         Use first character from each word to build table aliases in your queries.
Example: ra_customer_addresses_all RCAA, mtl_system_items MSI
·         Expressions/Nested function calls should be properly indented to come inside the calling function calls.
·         In the case of DECODE/REPLACE, each combination of ‘search’ and ‘replace’ string should appear on a new line.
Example: -
TO_DATE('10102002','DDMMYYYY')
DECODE(APS.class
      ,'INV', 'Invoice'
      ,'CM','Credit Memo')

DECODE( SIGN(SYSDATE-APS.due_date)
      ,-1, DECODE(APS.amount_due_remaining
                  ,0,'Past Due -Paid'
                  ,'Past Due-Open')
     , DECODE(APS.amount_due_remaining
                  ,0,'Paid'
                  ,'Open'))

·         Extensive comments need to be incorporated into the code.
·         Avoid the use of GO TO.
·         Instead of incorporating the programming logic in Triggers, Reports or Alerts, it is better to write the logic in a package procedure and call it from the Triggers, Reports or Alerts. The advantage is the package is compiled, parsed and stored in the database and therefore it is required primarily to fetch and execute.
·         Define packages and procedures. Anonymous PL/SQL procedure definitions are not acceptable except for data fixes.
·         Do not use “SELECT *” in your queries. Always write the required column names after the SELECT statement, like SELECT tab1.column1, tab1.column2, tab1.column3. This technique results in fewer disks IO and less network traffic and hence better performance.
·         Do not include explicit commits within the package.  In case the package requires processing of records that can create rollback segment problem, please put commits at logical transaction points with SAVEPOINT and ROLLBACK functions. This would be required in Databases versioned 8i and backwards. For databases versioned 9i and onwards, the UNDO Management feature, if implemented, does not require such provisions.




No comments:

Post a Comment

Best Blogger TipsGet Flower Effect