SQL Games We Can Play in PLSQL

Embed Size (px)

Citation preview

  • 8/8/2019 SQL Games We Can Play in PLSQL

    1/31

    Copyright 2000-2006 Steven Feuerstein - Page 1

    SQL Games We Can Playinside PL/SQL

    Steven [email protected]

    Quest Software

  • 8/8/2019 SQL Games We Can Play in PLSQL

    2/31

    Copyright 2000-2006 Steven Feuerstein - Page 2

    Software used in presentation

    You can d ow nlo ad all my trainingmaterials and dem o nstrati o n scriptsfr o m:

    All scripts I r u n may be o btained fr o m:

    name of file

    h ttp:// o racleplsqlpr o gramming.c o m/res ou rces. h tml

    h ttp:// o racleplsqlpr o gramming.c o m/d ow nlo ads/dem o .zip

  • 8/8/2019 SQL Games We Can Play in PLSQL

    3/31

    Copyright 2000-2006 Steven Feuerstein - Page 3

    Let the Games Begin!

    T u rb o ch arged SQL w ith BULKCOLLEC T and FORALLDeceptively simple SQL w ith tablef u ncti o nsCo de ab o ve t h e fray w ith rec o rd-levelDML.

  • 8/8/2019 SQL Games We Can Play in PLSQL

    4/31

    Copyright 2000-2006 Steven Feuerstein - Page 4

    Turbo-charged SQ L withBULK CO LLECT and FORA LL

    Impr o ve t h e perf o rmance o f m u lti-r ow SQLo perati o ns by an o rder o f magnit u de o r m o rew ith bu lk/array pr o cessing in PL/SQL!CREATE OR REPLACE PROCEDURE upd_for_dept (

    dept_in IN employee.department_id%TYPE,newsal_in IN employee.salary%TYPE)

    ISCURSOR emp_cur IS

    SELECT employee_id,salary,hire_dateFROM employee WHERE department_id = dept_in;

    BEGINFOR rec IN emp_cur LOOP

    UPDATE employee SET salary = newsal_in WHERE employee_id = rec.employee_id;

    END LOOP;END upd_for_dept;

    C onventional binds (and lots of them!)

  • 8/8/2019 SQL Games We Can Play in PLSQL

    5/31

    Copyright 2000-2006 Steven Feuerstein - Page 5

    Oracle server

    PL/SQL R u ntime Engine SQL Engine

    PL/SQL blockPr ocedu r al

    statementexecuto r

    SQL statementexecuto r

    FOR rec IN emp_cur LOOPUPDATE employee

    SET salary = ... WHERE employee_id =

    rec.employee_id;END LOOP;

    Performance penalty Performance penalty for many context for many context switches switches

    Conventional Bind

  • 8/8/2019 SQL Games We Can Play in PLSQL

    6/31

    Copyright 2000-2006 Steven Feuerstein - Page 6

    Enter the Bulk Bind

    Oracle server

    PL/SQL R u ntime Engine SQL Engine

    PL/SQL blockPr ocedu r al

    statementexecuto r

    SQL statementexecuto r

    FORALL indx INdeptlist.FIRST..deptlist.LAST

    UPDATE employeeSET salary = ...

    WHERE employee_id =deptlist(indx);

    Mu ch less overhead for Mu ch less overhead for context switching context switching

  • 8/8/2019 SQL Games We Can Play in PLSQL

    7/31

    Copyright 2000-2006 Steven Feuerstein - Page 7

    Use the FORA LL Bulk Bind Statement

    Instead o f exec u ting repetitive, individ u al DMLstatements, y ou can w rite y ou r c o de like t h is:

    Th ings t o be a w are o f: Y ou MUST know how to use collections to use this feature! O

    nly a single DML statement is allowed per F ORA

    LL. SQL%BULK_ ROW C O UNT returns the number of rows affected by each row in the binding array.

    P rior to O racle10g, the binding array must be sequentially filled. Use S AVE EX C EP TI O NS to continue past errors.

    PROCEDURE remove_emps_by_dept (deptlist dlist_t)ISBEGIN

    FORALL aDept IN deptlist.FIRST..deptlist.LASTDELETE FROM emp WHERE deptno = deptlist(aDept);

    END;

    bulktiming.sqlbulk_ r owcount.sql

    bulkexc.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    8/31

    Copyright 2000-2006 Steven Feuerstein - Page 8

    Use BU LK CO LLECT IN TO for Queries

    DECLARETYPE employees_aat IS TABLE OF employees%ROWTYPE

    INDEX BY BINARY_INTEGER;

    l_employees employees_aat;

    BEGINSELECT *BULK COLLECT INTO l_employees

    FROM employees;

    FOR indx IN 1 .. l_employees.COUNTLOOP

    process_employee (l_employees(indx));END LOOP;

    END;

    bulkcoll.sql

    Decla r e acollection of

    r eco r ds to holdthe que r ied data.

    Use BU LK CO LLE CT to

    r et r ieve all r ows.

    Ite r ate th r ough thecollection

    contents with aloop.

  • 8/8/2019 SQL Games We Can Play in PLSQL

    9/31

    Copyright 2000-2006 Steven Feuerstein - Page 9

    Limit the number of rows returned byBULK CO LLECT

    CREATE OR REPLACE PROCEDURE bulk_with_limit(deptno_in IN dept.deptno%TYPE)

    ISCURSOR emps_in_dept_cur IS

    SELECT *FROM emp

    WHERE deptno = deptno_in;

    TYPE emp_tt IS TABLE OF emp%ROWTYPE;emps emp_tt;

    BEGINOPEN three_cols_cur;LOOP

    FETCH emps_in_dept_curBULK COLLECT INTO emps

    LIMIT 100;

    EXIT WHEN emps.COUNT = 0;

    process_emps (emps);END LOOP;

    END bulk_with_limit;

    Use the LIMIT clause with theINTO to manage the amount

    of memo ry used with theBU LK CO LLE CT ope r ation.

    WARNING!

    BU LK CO LLE CT will not r aiseNO_DATA_FOUND if no r ows

    a r e found.

    Best to check contents of collection to confi r m thatsomething was r et r ieved.

    bulklimit.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    10/31

    Copyright 2000-2006 Steven Feuerstein - Page 10

    Tips and Fine Points

    Use b u lk binds in t h ese circ u mstances: R ecurring SQL statement in P L/SQL loop.O racle

    recommended threshold: five rows!

    Bu

    lk bind r u

    les: C an be used with any kind of collection; C ollectionsubscripts cannot be expressions; The collections must be densely filled (pre-10g); If error occurs, prior successful DML statements are N O T RO LLE D B AC K.

    Bu lk c o llects: C an be used with implicit and explicit cursors C ollection is always filled sequentially, starting at row 1

    emplu.pkgcfl_to_bulk*.*

  • 8/8/2019 SQL Games We Can Play in PLSQL

    11/31

    Copyright 2000-2006 Steven Feuerstein - Page 11

    D ynamic FORA LL Ex ample

    Th is example s h ow s t h e u se o f bu lk binding andco llecting, pl u s applicati o n o f th e RE T URNING cla u se.

    CREATE TYPE NumList IS TABLE OF NUMBER;CREATE TYPE NameList IS TABLE OF VARCHAR2(15);

    PROCEDURE update_emps (col_in IN VARCHAR2, empnos_in IN numList) ISenames NameList;

    BEGINFORALL indx IN empnos_in.FIRST .. empnos_in.LAST

    EXECUTE IMMEDIATE

    'UPDATE emp SET ' || col_in || ' = ' || col_in|| ' * 1.1 WHERE empno = :1RETURNING ename INTO :2'USING empnos_in (indx )RETURNING BULK COLLECT INTO enames ;

    ...END;

    Notice that empnos_inis indexed, but enames

    is not.

    Oracle9 i

  • 8/8/2019 SQL Games We Can Play in PLSQL

    12/31

    Copyright 2000-2006 Steven Feuerstein - Page 12

    D ynamic BU LK CO LLECT

    Now you can even avoid the OP EN FOR and justgrab your rows in a single pass!

    CREATE OR REPLACE PROCEDURE fetch_by_loc (loc_in IN VARCHAR2)IS

    TYPE numlist_t IS TABLE OF NUMBER ;TYPE namelist_t IS TABLE OF VARCHAR2 ( 15 );emp_cv sys_refcursor ;empnos numlist_t ;enames namelist_t ;sals numlist_t ;

    BEGINOPEN emp_cv FOR 'SELECT empno, ename FROM emp_' || loc_in ;FETCH emp_cv BULK COLLECT INTO empnos , enames ;

    CLOSE emp_cv ;

    EXECUTE IMMEDIATE 'SELECT sal FROM emp _' || loc_inBULK COLLECT INTO sals ;

    END;With O r acle9iR2

    you can also fetchinto collections of

    r eco r ds.

    Oracle9 i

  • 8/8/2019 SQL Games We Can Play in PLSQL

    13/31

    Copyright 2000-2006 Steven Feuerstein - Page 13

    Ex cellent Ex ception Handlingfor Bulk Operations in Oracle 9i D atabase R2

    Allows you to continue past errors andobtain error information for each individualoperation (for dynamic and static SQ L).

    CREATE OR REPLACE PROCEDURE load_books (books_in IN book_obj_list_t)IS

    bulk_errors EXCEPTION;PRAGMA EXCEPTION_INIT ( bulk_errors, -24381 );

    BEGINFORALL indx IN books_in.FIRST..books_in.LAST

    SAVE EXCEPTIONSINSERT INTO book values (books_in(indx));

    EXCEPTION

    WHEN BULK_ERRORSTHENFOR indx in 1.. SQL%BULK_EXCEPTIONS.COUNTLOOP

    log_error ( SQL%BULK_EXCEPTIONS(indx));END LOOP;

    END;

    Allows p r ocessing of allr ows, even afte r an

    e rr o r occu r s.

    New cu r so r att r ibute, a pseudo-

    collection

    bulkexc.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    14/31

    Copyright 2000-2006 Steven Feuerstein - Page 14

    Should you ever use a cursor FOR loop?

    Oracle10g will automatically optimize cursorFOR loops to perform at levels comparable toBULK CO LLECT! So what the heck, keep or write your cursor FOR

    loops -- at least if they contain no DML .Also stick with a cursor FOR loop .... If you want to do comple x DM L processing on each

    row as it is queried and possibly halt furtherfetching, and you can't use SAV E EXCEPTIONS .

    Otherwise, moving to BU LK CO LLECT andFORA LL is a smart move!

    10 g_optimize_cfl.sqlcfl_vs_bulkcollect.sql

    cfl_to_bulk.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    15/31

    Copyright 2000-2006 Steven Feuerstein - Page 15

    M ore fle x ibility with FORA LL

    In Oracle10g, t h e FORALL driving array n o lo nger needs t o be pr o cessed seq u entially.Use t h e INDICES OF cla u se t o u se o nly t h er ow nu mbers defined in another array.Use t h e VALUES OF cla u se t o u se o nly t h ev alues defined in an o th er array.

    Or acle 10 g

  • 8/8/2019 SQL Games We Can Play in PLSQL

    16/31

    Copyright 2000-2006 Steven Feuerstein - Page 16

    Using IN D IC ES OF

    It o nlypr o cessesth e r ow sw ith r ow nu mbersmatc h ingth e d efine d rows o f th e

    drivingarray.

    Or acle 10 g

    DECLARETYPE employee_aat IS TABLE OF employee.employee_id%TYPE

    INDEX BY PLS_INTEGER;l_employees employee_aat;TYPE boolean_aat IS TABLE OF BOOLEAN

    INDEX BY PLS_INTEGER;l_employee_indices boolean_aat;

    BEGINl_employees (1) := 7839;l_employees (100) := 7654;l_employees (500) := 7950;--l_employee_indices (1) := TRUE;l_employee_indices (500) := TRUE;--FORALL l_index IN INDICES OF l_employee_indices

    UPDATE employeeSET salary = 10000

    WHERE employee_id = l_employees (l_index);END;

    10g_indices_ o f.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    17/31

    Copyright 2000-2006 Steven Feuerstein - Page 17

    Using VA LUES OF

    It o nlypr o cessesth e r ow s

    w ith r ow nu mbersmatc h ingth e c ontent o f a r ow in

    th e drivingarray.

    Or acle 10 g

    DECLARETYPE employee_aat IS TABLE OF employee.employee_id%TYPE

    INDEX BY PLS_INTEGER;l_employees employee_aat;TYPE indices_aat IS TABLE OF PLS_INTEGER

    INDEX BY PLS_INTEGER;l_employee_indices indices_aat;

    BEGINl_employees (-77) := 7820;l_employees (13067) := 7799;l_employees (99999999) := 7369;--l_employee_indices (100) := -77;l_employee_indices (200) := 99999999;--

    FORALL l_index IN VALUES OF l_employee_indicesUPDATE employeeSET salary = 10000

    WHERE employee_id = l_employees (l_index);END;

    10g_val u es_ o f.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    18/31

    Copyright 2000-2006 Steven Feuerstein - Page 18

    Table Functions

    A table f u ncti o n is a f u ncti o n t h at y ou can call in t h eFROM cla u se o f a q u ery, and h ave it be treated as if it w ere a relational table.T

    able f u

    nctio

    ns allow

    you

    to

    perf o

    rm arbitrarilyco mplex transf o rmati o ns o f data and t h en make t h atdata available t h r ou gh a q u ery. Not everything can be done in SQL.

    Co mbined w ith REF CURSORs, y ou can n ow m o reeasily transfer data fr o m w ith in PL/SQL t o h o stenvir o nments. J ava, for example, works very smoothly with cursor variables

  • 8/8/2019 SQL Games We Can Play in PLSQL

    19/31

    Copyright 2000-2006 Steven Feuerstein - Page 19

    Applications for pipelined functions

    Exec u tio n f u ncti o ns in parallel. In O racle9i Database R elease 2 and above, you can use the

    PARA LLE L_ E N ABLE clause to allow your pipelined

    function to participate fully in a parallelized query. C ritical in data warehouse applications.

    Impr o ve speed o f delivery o f data t o w ebpages. Use a pipelined function to "serve up" data to the webpage

    and allow users to being viewing and browsing, evenbefore the function has finished retrieving all of the data.

  • 8/8/2019 SQL Games We Can Play in PLSQL

    20/31

    Copyright 2000-2006 Steven Feuerstein - Page 20

    Building a table function

    A table f u ncti o n m u st ret u rn a nested table o r varray based o n a sc h ema-defined type, o r typedefined in a PL/SQL package.Th e f u ncti o n h eader and t h e w ay it is calledm u st be SQL-c o mpatible: all parameters u seSQL types; n o named n o tati o n. In some cases (streaming and pipelines functions), the IN

    parameter must be a cursor variable -- a query result set.

  • 8/8/2019 SQL Games We Can Play in PLSQL

    21/31

    Copyright 2000-2006 Steven Feuerstein - Page 21

    Simple table function e xample

    Ret u rn a list o f names as a nested table, andth en call t h at f u ncti o n in t h e FROM cla u se.

    CREATE OR REPLACE FUNCTION lotsa_names (

    base_name_in IN VARCHAR2, count_in IN INTEGER )RETURN names_nt

    ISretval names_nt := names_nt ();

    BEGINretval.EXTEND (count_in);

    FOR indx IN 1 .. count_inLOOP

    retval (indx) := base_name_in || ' ' || indx;

    END LOOP;

    RETURN retval;END lotsa_names; tabf

    u nc_scalar.sql

    SELECT column_valueFROM TABLE (

    lotsa_names ('Steven', 100)) names;

    COLUMN_VALUE

    ------------Steven 1...Steven 100

  • 8/8/2019 SQL Games We Can Play in PLSQL

    22/31

    Copyright 2000-2006 Steven Feuerstein - Page 22

    Streaming data with table functions

    You can u se table f u ncti o ns t o "stream" data t h r ou gh several stages w ith in a single SQL statement.

    CREATE TYPE tickertype AS OBJECT (ticker VARCHAR2 (20)

    , pricedate DATE, pricetype VARCHAR2 (1), price NUMBER

    );

    CREATE TYPE tickertypeset AS TABLE OF tickertype;/

    CREATE TABLE tickertable (ticker VARCHAR2(20),

    pricedate DATE, pricetype VARCHAR2(1), price NUMBER)

    /

    tabf u nc_streaming.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    23/31

    Copyright 2000-2006 Steven Feuerstein - Page 23

    Streaming data with table functions - 2

    In th is example, transf o rm eac h r ow o f th est o cktable int o two r ow s in t h e tickertable.

    CREATE OR REPLACE PACKAGE refcur_pkgIS

    TYPE refcur_t IS REF CURSOR RETURN stocktable%ROWTYPE;

    END refcur_pkg;/

    CREATE OR REPLACE FUNCTION stockpivot (dataset refcur_pkg.refcur_t)RETURN tickertypeset ...

    BEGININSERT INTO tickertable

    SELECT *FROM TABLE (stockpivot (CURSOR (SELECT *

    FROM stocktable)));END;/

    tabf u nc_streaming.sql

  • 8/8/2019 SQL Games We Can Play in PLSQL

    24/31

    Copyright 2000-2006 Steven Feuerstein - Page 24

    Use pipelined functions to enhanceperformance .

    Pipelined f u ncti o ns all ow you to ret u rn dataiteratively, async h r o nou s t o terminati o n o f th ef u ncti o n. As data is produced within the function, it is passed back

    to the calling process/query.

    Pipelined f u

    nctio

    ns can be defined to

    su

    ppo

    rtparallel exec u tio n. Iterative data processing allows multiple processes to

    work on that data simultaneously.

    CREATE FUNCTION StockPivot (p refcur_ p kg.refcur_t ) RETURN TickerTy p eSet PIPELINED

  • 8/8/2019 SQL Games We Can Play in PLSQL

    25/31

    Copyright 2000-2006 Steven Feuerstein - Page 25

    Piping rows out from a pipelined function

    CREATE FUNCTION stockpivot (p refcur_pkg.refcur_t)RETURN tickertypesetPIPELINED

    ISout_rec tickertype :=

    tickertype (NULL, NULL, NULL);in_rec p%ROWTYPE;

    BEGINLOOPFETCH p INTO in_rec;EXIT WHEN p%NOTFOUND;out_rec.ticker := in_rec.ticker;out_rec.pricetype := 'O';out_rec.price := in_rec.openprice;

    PIPE ROW (out_rec);END LOOP;CLOSE p;

    RETURN;END;

    tabf u nc_set u p.sqltabf u nc_pipelined.sql

    Add P IPEL INEDke ywo r d to heade r

    P ipe a r ow of databack to calling block

    o r que ry

    RETURN...nothing atall!

  • 8/8/2019 SQL Games We Can Play in PLSQL

    26/31

    Copyright 2000-2006 Steven Feuerstein - Page 26

    Enabling Parallel Ex ecution

    Th e table f u ncti o n's parameter list m u st c o nsist o nlyo f a single strongly-type d REF CURSOR.Inclu de t h e PARALLEL_ENABLE h int in t h e pr o gramh eader. C hoose a partition option that specifies how the function's

    execution should be partitioned. " AN Y " means that the results are independent of the order in which

    the function receives the input rows (through the RE F C U R S OR ).

    {[ ORDER | CLUSTER ] BY column_list } PARALLEL_ENABLE ( { PARTITION p BY

    [ ANY | (H ASH | RANGE ) column_list ]} )

  • 8/8/2019 SQL Games We Can Play in PLSQL

    27/31

    Copyright 2000-2006 Steven Feuerstein - Page 27

    Table functions - Summary

    T able f u ncti o ns o ffer significant ne w flexibilityf o r PL/SQL devel o pers.Co nsider u sing t h em w h en y ou ... Need to pass back complex result sets of data through the

    SQL layer (a query); W ant to call a user defined function inside a query and

    execute it as part of a parallel query.

  • 8/8/2019 SQL Games We Can Play in PLSQL

    28/31

    Copyright 2000-2006 Steven Feuerstein - Page 28

    Record-based DM L

    PL/SQL rec o rds (similar in str u ctu re t o a r ow in a table) o ffer p ow erf u l w ays t o manip u latedata Pri o r to Oracle9i R2, h ow ever, rec o rds c ou ld n o t

    be u sed in DML statementsTh at restricti o n h as n ow been lifted You can INSER T specifying a rec o rd rat h er t h an

    individ u al fields o f th e rec o rd You can UPDA T E an entire r ow w ith a rec o rd

    Oracle9 i

  • 8/8/2019 SQL Games We Can Play in PLSQL

    29/31

    Copyright 2000-2006 Steven Feuerstein - Page 29

    Th is example s h ow s a rec o rd-based insertinside t h e h igh -speed FORALL statement

    DECLARETYPE book_list_t IS TABLE OF books%ROWTYPE;

    my_books book_list_t := book_list_t();BEGIN

    my_books.EXTEND (2);

    my_books(1).isbn := '1-56592-335-9'; my_books(1).title := 'ORACLE PL/SQL PROGRAMMING';

    my_books(2).isbn := '0-596-00121-5'; my_books(2).title := 'ORACLE PL/SQL BEST PRACTICES';

    FORALL indx IN my_books.FIRST .. my_books.LASTINSERT INTO books VALUES my_books(indx);

    END;

    Record-based Inserts

  • 8/8/2019 SQL Games We Can Play in PLSQL

    30/31

    Copyright 2000-2006 Steven Feuerstein - Page 30

    You can o nly u pdate t h e entire ROW, and n o t as u bset via, say, a pr o grammer-defined rec o rd type

    DECLARE my_book books%ROWTYPE;

    BEGIN my_book.isbn := '1-56592-335-9'; my_book.title := 'ORACLE PL/SQL PROGRAMMING'; my_book.summary := 'General user guide and reference'; my_book.author := 'FEUERSTEIN, STEVEN AND BILL PRIBYL'; my_book.page_count := 950; -- new page count for 3rd edition

    UPDATE booksSET ROW = my_book

    WHERE isbn = my_book.isbn;END;

    Record-based Updates

  • 8/8/2019 SQL Games We Can Play in PLSQL

    31/31

    Copyright 2000-2006 Steven Feuerstein - Page 31

    Stop taking SQ L for granted!

    Every SQL statement is a h ard-c o ding o f you r data str u ctu res in y ou r c o de, s o ... C ontrol your SQL.

    Avoid writing SQL. And fully leverage P L/SQL when you do write SQL.T ake advantage o f key PL/SQL f u ncti o nality. F ORA LL BULK C O LLE C T Table functions R ecord-based DML