Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Mailing Lists -> Oracle-L -> Re: pl/sql open cursor question

Re: pl/sql open cursor question

From: Carel-Jan Engel <cjpengel.dbalert_at_xs4all.nl>
Date: Tue, 30 Dec 2003 02:49:27 -0800
Message-ID: <F001.005DB416.20031230024927@fatcity.com>



Jared,

Point taken. I should do some testing instead of publish an opinion. I still do not like the constraction, but that's a matter of taste.

I have done some testing as well, because I think you were somehow comparing apples and oranges: function a uses an implicit cursor, whereas function b has an explicit cursor. So I ran a, b and b2 through Tom Kyte's runstats harness, but found no significant differences:


Functions:

create or replace function a return varchar2
is
begin
   for srec in (select dummy from ctest)
   loop
      return srec.dummy;
   end loop;
   return null;
end;
/

create or replace function b return varchar2
is
   cursor c1
   is
   select dummy
   from ctest;
   v_dummy varchar2(1) := null;

begin
   open c1;
   fetch c1 into v_dummy;
   close c1;
   return v_dummy;
end;
/

create or replace function b2 return varchar2
is
   v_dummy varchar2(1) := null;
begin
   select dummy
   into   v_dummy
   from   ctest;
   return v_dummy;

   exception
   when no_data_found
  then return null;
end;
/


Testrun:

set serveroutput on size 20000
exec runstats_pkg.rs_start;
declare
  l_loop   number := 0;
  l_dummy  varchar2(1);
begin
  for l_loop in 1..1000
  loop
    l_dummy := a;
  end loop;
end;
/
exec runstats_pkg.rs_middle;
declare
  l_loop   number := 0;
  l_dummy  varchar2(1);
begin
  for l_loop in 1..1000
  loop
    l_dummy := b;
  end loop;
end;
/
exec runstats_pkg.rs_stop(1);

For the test of b2 b was simply replaced by b2)

The results:

a vs b:

Run1 ran in 18 hsecs
Run2 ran in 18 hsecs
run 1 ran in 100% of the time

Name                                Run1      Run2      Diff
LATCH.enqueue hash chains             28        26        -2
LATCH.enqueues                        28        26        -2
LATCH.library cache                2,067     2,069         2
LATCH.redo allocation                 33        31        -2
LATCH.library cache pin            2,046     2,048         2
STAT...enqueue requests               16        14        -2
STAT...enqueue releases               16        14        -2
STAT...calls to get snapshot s     4,011     4,009        -2
STAT...active txn count during        16         8        -8
STAT...consistent gets - exami        16         8        -8
STAT...calls to kcmgcs                16         8        -8
STAT...cleanout - number of kt        16         8        -8
STAT...CPU used by this sessio        33        23       -10
STAT...consistent gets             3,026     3,016       -10
STAT...CPU used when call star        33        23       -10
STAT...redo entries                   46        34       -12
LATCH.cache buffers chains         6,226     6,212       -14
STAT...db block changes               63        49       -14
STAT...db block gets                 100        68       -32
STAT...session logical reads       3,126     3,084       -42
STAT...redo size                  30,224    29,720      -504
STAT...recursive calls             1,001     2,001     1,000

Run1 latches total versus runs -- difference and pct
Run1      Run2      Diff     Pct
11,543    11,525       -18 100.16%

a vs b2:

Run1 ran in 17 hsecs
Run2 ran in 23 hsecs
run 1 ran in 73.91% of the time

Name                                Run1      Run2      Diff
LATCH.enqueue hash chains             28        26        -2
LATCH.enqueues                        28        26        -2
LATCH.library cache                2,067     2,069         2
STAT...bytes received via SQL*       984       986         2
LATCH.library cache pin            2,046     2,048         2
LATCH.redo allocation                 34        31        -3
STAT...CPU used by this sessio        32        29        -3
STAT...enqueue releases               17        14        -3
STAT...enqueue requests               17        14        -3
STAT...CPU used when call star        32        29        -3
STAT...calls to get snapshot s     4,013     4,009        -4
STAT...active txn count during        17         8        -9
STAT...cleanout - number of kt        17         8        -9
STAT...calls to kcmgcs                17         8        -9
STAT...consistent gets - exami        17         8        -9
STAT...consistent gets             3,029     3,016       -13
STAT...recursive cpu usage            12        25        13
STAT...redo entries                   49        34       -15
STAT...db block changes               69        48       -21
LATCH.cache buffers chains         6,235     6,207       -28
STAT...db block gets                 111        66       -45
STAT...session logical reads       3,140     3,082       -58
STAT...redo size                  30,648    29,660      -988
STAT...recursive calls             1,001     2,001     1,000

Run1 latches total versus runs -- difference and pct
Run1      Run2      Diff     Pct
11,557    11,519       -38 100.33%

(9.2.0.2/SuSE 8.1)

I find it quite strange that results vary from run to run. E.g. in a vs b active txn count was 16 for a, whilst it was 17 for a vs. b2. Why this difference?
B variants are consequently cheaper in redo size, session logical reads. Recursive calls is conseqently 1000 higher for b/b2.
What counts is runtime, and a and b have no differences, b2, is appr. 25% slower. b/b2 consume slightly less latches, but the diff is < 1 %.

So, IMHO what remains is the question of taste. I started 22 years ago as software engineer, worked in R&D departments (of commercial software firms) and built a 4GL, including a compiler and a universal interpreter for the code produced. Maybe bearing the burdens of my career as a stone-age 'C'-developer influences my 'taste' of beautiness of code (or the lack off it).
Unless I've put some flaws in my testruns (which I'm glad to hear of), I rest my case.

Regards, Carel-Jan

===
If you think education is expensive, try ignorance. (Derek Bok)
===

At 17:44 28-12-03 -0800, you wrote:
Carel,

It might seem that the loop construct would be more expensive, but
it didn't appear that way on my test system. ( 9.2.0.4, RH 8.0 )

function a:

create or replace function a return varchar2
is
begin
   for srec in (select dummy from ctest)
   loop
      return srec.dummy;
   end loop;
   return null;
end;
/


function b:

create or replace function b return varchar2
is
   cursor c1
   is
   select dummy
   from ctest;

   v_dummy varchar2(1) := null;

begin
   open c1;
   fetch c1 into v_dummy;
   close c1;
   return v_dummy;
end;
/

The resource consumption for a 1000 iterations of each: ( a is the first
column )

17:38:42 poirot.jks.com - jkstill@ts01 SQL> @run_stats

NAME                                           RUN1       RUN2       DIFF
---------------------------------------- ---------- ---------- ----------
LATCH.Consistent RBA                              0          1          1
LATCH.cache buffers lru chain                     1          0         -1
LATCH.lgwr LWN SCN                                0          1          1
LATCH.mostly latch-free SCN                       0          1          1
LATCH.session idle bit                            0          1          1
STAT...calls to get snapshot scn: kcmgss       3012       3013          1
STAT...calls to kcmgcs                            7          6         -1
STAT...cleanout - number of ktugct calls          0          1          1
STAT...consistent gets - examination              0          1          1
STAT...session cursor cache hits                  1          2          1
STAT...parse count (total)                        1          2          1
STAT...opened cursors current                     1          2          1
STAT...opened cursors cumulative                  1          2          1
STAT...messages sent                              0          1          1
STAT...free buffer requested                      1          0         -1
STAT...execute count                           1003       1004          1
STAT...deferred (CURRENT) block cleanout          4          3         -1
 applications

STAT...calls to kcmgas                            0          1          1
STAT...user commits                               0          1          1
STAT...active txn count during cleanout           0          1          1
LATCH.enqueues                                    0          1          1
LATCH.dml lock allocation                         0          2          2
LATCH.session allocation                          0          2          2
STAT...db block changes                          25         27          2
STAT...enqueue releases                           0          2          2
STAT...consistent gets                         3010       3012          2
LATCH.cache buffers chains                     6130       6133          3
STAT...redo entries                              17         20          3
STAT...recursive cpu usage                        4          7          3
STAT...db block gets                             30         33          3
LATCH.redo writing                                0          3          3
LATCH.undo global data                            1          4          3
LATCH.library cache                               7          4         -3
LATCH.enqueue hash chains                         0          4          4
LATCH.redo allocation                            18         22          4
LATCH.library cache pin                           7          3         -4
LATCH.messages                                    0          5          5
STAT...session logical reads                   3040       3045          5
STAT...commit cleanouts                           0          7          7
STAT...commit cleanouts successfully com          0          7          7
pleted

STAT...redo size                              27184      27820        636
STAT...recursive calls                         2004       3007       1003

42 rows selected.

The for loop actually appears to be somewhat less expensive in terms
of database resources.

Jared


On Sun, 2003-12-28 at 11:39, Carel-Jan Engel wrote:
> What I don't understand is the loop construction:
>
> Actually only one (row) is read form the cursor, and then the function is
> left with a return. Because it's an unconditional return, the code within
> the loop will either execute  once, or never. When no data is found NULL is
> returned. When an error occurs NULL is returned as well. So, why a loop?
>
> Wouldn't it be better to have something like:
>
> create or replace function XYZ(gid in number) return varchar2 is
>    l_c1   tab1.C1%TYPE;    /* local variable to store C1 */
> begin
>    select c1
>    into l_c1
>    from    tab1
>    where  id = gid;
>
>    return  l_c1;
>
> exception
>    when no_data_found
>      then return <some_error_code>;  /* let the caller know that no data is
> found */
>    when others
>      then return 'ERROR: '||TO_CHAR(SQLCODE); /* return the error-code,
> preceded by the text ERROR for identification */
> end;
>
> Sure, a loop prevents an ORA-1422, but I don't think a loop construction
> should be abused for this. Just think about all loop controlling code that
> needs to be set up by the interpreter. tab1.ID should be unique, so a 1422
> normally cannot occur. Robust programming however asks us to prevent any
> error. I would prefer to think about how a 1422 should be handled, and
> write some code accordingly.
>
> Regards, Carel-Jan
>
> ===
> If you think education is expensive, try ignorance. (Derek Bok)
> ===
>
>
> At 09:39 28-12-03 -0800, you wrote:
> >Hi
> >
> >if  we assume it is  implements this way (see below) there will only be
> >one cursor since c_gid
> >is a bind variable and there for the cursor will be sharded from  call to
> >call of the function.
> >
> >create or replace function XYZ (gid in number) return varchar2 is
> >   cursor cur1(c_gid number) is select C1 from tab1 where id = c_gid;
> >begin
> >   for x in cur1(gid) loop
> >     return x.c1;
> >   end loop;
> >   return null;
> >exception
> >   when others then return null;
> >end;
> >
> >It will only be one coursor
> >
> >Guang Mei wrote:
> >>
> >>I have a function like below (psudo code). If cursor cur1 have multiple
> >>rows, would the code leave the cursor open when this function is called?
> >>So if this function is called 1000 times, I would have 1000 open cursors?
> >>
> >>function XYZ(gid in number) return varchar2 is
> >>   cursor cur1 is select C1 from tab1 where ID = gid;
> >>begin
> >>   for x in cur1 loop
> >>     return x.c1;
> >>   end loop;
> >>   return null;
> >>exception
> >>   when others then return null;
> >>end;
> >>
> >>
> >
> >--
> >
> >Best regards/Venlig hilsen
> >
> ><mailto:peter.gram@miracleas.dk>Peter Gram
> >
> ><http://www.miracleas.dk/>Miracle<http://www.miracleas.dk/> A/S
> >Kratvej 2
> >DK - 2760 Måløv
> >Cell:  (+45) 2527 7107
> >Phone: (+45) 4466 8855
> >Fax:   (+45) 4466 8856
> >Home:  (+45) 3874 5696
> >Email: <mailto:peter.gram@miracleas.dk>peter.gram@miracleas.dk


--
Please see the official ORACLE-L FAQ: http://www.orafaq.net
--
Author: Jared Still
  INET: jkstill@cybcon.com

Fat City Network Services    -- 858-538-5051 http://www.fatcity.com
San Diego, California        -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: ListGuru@fatcity.com (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).
-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.net
-- 
Author: Carel-Jan Engel
  INET: cjpengel.dbalert_at_xs4all.nl

Fat City Network Services    -- 858-538-5051 http://www.fatcity.com
San Diego, California        -- Mailing list and web hosting services
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: ListGuru_at_fatcity.com (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).
Received on Tue Dec 30 2003 - 04:49:27 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US