Boost Performance with PL/SQL Programming Best Practices


Published on

Conferencia en #LAOTNTour Ecuador Tim Hall

Published in: Technology
1 Comment
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Boost Performance with PL/SQL Programming Best Practices

  1. 1. Boost Performance with PL/SQL Programming Best Practices Tim Hall Oracle ACE Director Oracle ACE of the Year 2006 OakTable Network OCP DBA (7, 8, 8i, 9i, 10g, 11g) OCP Advanced PL/SQL Developer Oracle Database: SQL Certified Expert Books Oracle PL/SQL Tuning Oracle Job Scheduling
  2. 2. Overview of the PL/SQL Engine PL/SQL Engine Procedural PL/SQL PL/SQL Statement Block Block Executor SQL Statement Executor Oracle Server• PL/SQL contains procedural and SQL code.• Each type of code is processed separately.• Switching between code types causes an overhead.• The overhead is very noticeable during batch operations.• Bulk binds minimize this overhead.
  3. 3. Bulk-Binds – BULK COLLECT• Populate collections directly SELECT * from SQL using BULK BULK COLLECT INTO l_tab FROM tab1; COLLECT.• Demo OPEN c1; LOOP• Collections are held in FETCH c1 memory, so watch collection BULK COLLECT INTO l_tab LIMIT 1000; sizes. EXIT WHEN l_tab.count = 0;• Demo -- Process chunk.• Implicit array processing END LOOP; CLOSE c1; introduced in 10g.• Demo FOR cur_rec IN (SELECT * FROM tab1) LOOP -- Process row. END LOOP;
  4. 4. Bulk-Binds – FORALL• Bind data in collections into DML FORALL i IN l_tab.FIRST .. l_tab.LAST INSERT INTO tab2 VALUES l_tab(i); using FORALL.• Demo• Use INDICIES OF and VALUES OF for sparse collections.• Use SQL%BULK_ROWCOUNT to return the number of rows affected by each statement.• The SAVE EXCEPTIONS allows bulk operations to complete.• Exceptions captured in SQL %BULK_EXCEPTIONS.
  5. 5. Short-Circuit Evaluations and Logic Order• If left side of an OR expression is IF l_continue OR fn_rec_count > 10 THEN TRUE, the whole expression is TRUE. -- Do Something TRUE OR FALSE = TRUE END IF; TRUE OR TRUE = TRUE• If the left side of an AND expression is IF l_continue AND fn_rec_count > 10 THEN FALSE, the whole expression is -- Do Something END IF; FALSE. FALSE AND FALSE = FALSE FALSE AND TRUE = FALSE IF l_rec_type = POPULAR THEN• In these cases Oracle doesn’t evaluate -- Do Something ELSIF l_rec_type = MEDIUM THEN the second half of the expresson. -- Do Something• Place “least expensive” tests to the ELSIF l_rec_type = ‘UNPOPULAR THEN -- Do Something left of expressions. END IF;• Evaluations of ELSIF and CASE CASE l_rec_type statements stops once a match is WHEN POPULAR THEN found. -- Do Something WHEN MEDIUM THEN• Place the “most likely outcomes” at -- Do Something the top of branching constructs. WHEN ‘UNPOPULAR THEN -- Do Something END CASE;
  6. 6. Declarations in Loops• Code within loops gets run -- Bad idea. multiple times. FOR i IN 1 .. 100 LOOP DECLARE• Variable declarations and l_str VARCHAR2(200); BEGIN procedure/function calls in loops -- Do Something. impact on performance. END; END LOOP;• Simplify code within loops to improve performance. -- Better idea.• Oracle 11g offsets solves some of DECLARE the performance impact with l_str VARCHAR2(200); BEGIN automatic subprogram inlining. FOR i IN 1 .. 100 LOOP• Don’t stop using modular code -- Do Something. END LOOP; because of this. Keep these END; results in context!
  7. 7. Efficient Function Calls• When functions are called in SELECT SQRT(num_val), COUNT(*) AS amount SQL statements, minimize the FROM tab1 GROUP BY SQRT(num_val); number of calls by filtering the data if possible. SELECT SQRT(num_val), amount FROM (SELECT num_val, COUNT(*) AS amount• Demo FROM tab1 GROUP BY num_val))• When function calls are present in the WHERE clause, CREATE INDEX efficient_functions_fbidx ON efficient_functions (SQRT(data_length)); consider function-based indexes. SELECT COUNT(*)• Demo FROM efficient_functions ef WHERE SQRT(ef.data_length) = 5.47722558;• Consider maintenance costs, disk space requirements and global affect of function-based indexes.
  8. 8. Using the NOCOPY Hint• The NOCOPY hint allows OUT and IN OUT parameter to be passed by-reference, rather than by-value. PROCEDURE myproc (p_tab IN OUT NOCOPY CLOB) IS BEGIN -- Do something. END;• By-value: Procedure uses temporary buffer. Copies value back on successful completion.• By-reference: Procedure uses original memory location directly.• Beware of affect of error handling and parameter aliasing on parameter values.• It’s a hint, not a directive, so it can be ignored
  9. 9. PLSQL_OPTIMIZE_LEVEL• The PLSQL_OPTIMIZE_LEVEL parameter was introduced in 10g to control how much optimization the compiler performs: – 0 : Code will compile and run in a similar way to 9i and earlier. New actions of BINARY_INTEGER and implicit array processing lost. – 1 : Performs a variety of optimizations, including elimination of unnecessary computations and exceptions. Does not alter source order. – 2 : Performs additional optimizations, including reordering source code if necessary. The is the default setting in 10g and 11g. – 3 : New in 11g. Yet more optimizations and subprogram inlining.• The optimization level associated with the library unit is visible using the %_PLSQL_OBJECT_SETTINGS view.• Adjust only if package load times are adversely affected. ALTER SESSION SET PLSQL_OPTIMIZE_LEVEL=0; ALTER PROCEDURE my_big_package COMPILE;
  10. 10. Native Compilation of PL/SQL• By default PL/SQL is interpreted.• Set PLSQL_CODE_TYPE parameter to NATIVE before creating or compiling code. ALTER SESSION SET PLSQL_CODE_TYPE=NATIVE; ALTER PROCEDURE my_proc COMPILE;• Prior to 11g, native compilation converts PL/SQL to C, which is then compiled in shared libraries.• Improves performance of procedural logic.• Demo• Doesn’t affect the speed of database calls.• The PLSQL_CODE_TYPE associated with the library unit is visible using the %_PLSQL_OBJECT_SETTINGS view.
  11. 11. INTEGER Types• NUMBER and it’s subtypes use an Oracle internal format, rather than the machine arithmetic.• INTEGER and other constrained type need additional runtime checks compared to NUMBER.• PLS_INTEGER uses machine arithmetic to reduce overhead.• BINARY_INTEGER is slow in 8i and 9i, but fast in 10g because it uses machine arithmetic.• Demo• 11g includes SIMPLE_INTEGER which is quick in natively compiled code.• Use the appropriate datatype for the job.
  12. 12. BINARY_FLOAT and BINARY_DOUBLE• New in 10g.• They use machine arithmetic, like PLS_INTEGER and BINARY_INTEGER.• Require less storage space.• Fractional values not represented precisely, so avoid when accuracy is important.• Approximately twice the speed of NUMBER.• Demo• Use the appropriate datatype for the job.
  13. 13. Avoid unnecessary PL/SQL• SQL is usually quicker than PL/SQL.• Don’t use UTL_FILE to read text files if you can use external tables.• Don’t write PL/SQL merges if you can use the MERGE statement.• Use multi-table inserts, rather than coding them manually.• Use DML error logging (DBMS_ERRLOG) to trap failures in DML, rather than coding PL/SQL.• All use DML, which is easily parallelized.
  14. 14. Quick Points• Use ROWIDs for update when data is selected for subsequent update.• Use built-in functions where possible. They are usually more efficient that your custom code.• Datatype conversions take time. Reduce them.• Implicit cursors are faster and do more exception checking than explicit cursors. Use them.• Hide performance problems by decoupling. Queue requests and process in batch.
  15. 15. The End…• Questions?• References:• Demos: