Skip to Main Content
  • Questions
  • RefCursors Vs Pipelined Functions (11g)

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Nikhil.

Asked: January 11, 2017 - 7:00 am UTC

Last updated: January 12, 2017 - 3:58 pm UTC

Version: 11.2.0

Viewed 10K+ times! This question is

You Asked

Hi Team,

Could you please go through below scenario -
I have a stored procedure lets say
SP_BULK_PDF_CARD_DATA( pindate IN VARCHAR2,
vcountry IN VARCHAR2,
vregion IN VARCHAR2,
vpdfemailflag IN VARCHAR2,
vcardnumbers IN VARCHAR2,
curscarddata OUT types.cursor_type,
cursormclodge OUT types.cursor_type)

Two OUT ref Cursors fetches around 70,000 records and for each record again some internal procedures gets called..

We have done some changes to Queries used to fetch these REF cursors data.

I need some inputs on -
Since procedures returns control back when both these cursors SQL's gets executed holding around 70,000 records.
To avoid this, Converting this procedure into Pipelined function, will that help, since pipelined function returns rows as soon as they are available?

Could you please share your views..

and Chris said...

I'm not sure what problem you're trying to solve by switching to a pipelined function.

If you have an out parameter is a refcursor, your procedure should just open it. This is "instant". It's executing+fetching that takes time.

For example, I've created a function with a wait to have a query that takes a few seconds to run. And a procedure that opens a refcursor calling this:

create or replace function f 
  return int as 
begin
  dbms_lock.sleep(5);
  return 1;
end;
/

create or replace procedure p (cur out sys_refcursor) is
begin
  open cur for 
    select f from dual;
end p;
/


Running the procedure is fast. But displaying the results takes time:

SQL> set timing on
SQL> select f from dual;

         F
----------
         1

Elapsed: 00:00:05.47
SQL>
SQL> exec p(:c);

PL/SQL procedure successfully completed.

Elapsed: 00:00:00.35
SQL>
SQL> print :c;

         F
----------
         1

Elapsed: 00:00:05.46


You see a similar runtime with the pipelined function:

SQL> create or replace type nums as object (f int);
  2  /

Type created.

Elapsed: 00:00:00.33
SQL> create or replace type nums_t as table of nums;
  2  /

Type created.

Elapsed: 00:00:00.33
SQL>
SQL> create or replace function pipeline
  2    return nums_t pipelined as
  3  begin
  4    for rws in (
  5      select f from dual
  6    ) loop
  7      pipe row(nums(rws.f));
  8    end loop;
  9
 10    return ;
 11  end;
 12  /

Function created.

Elapsed: 00:00:00.33
SQL>
SQL> select * from table(pipeline());

         F
----------
         1

Elapsed: 00:00:05.47


So if you're fetching the same number of rows, you should see total runtime similar between a refcursor and pipelined function.

So... what precisely are you trying to do? Show us all your code!

Rating

  (1 rating)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Looping 70k records

Nikhil Patil, January 12, 2017 - 11:27 am UTC

Hi Chris,
Procedure is send REFCURSOR to JAVA, SQL is shared in
https://livesql.oracle.com/apex/livesql/s/ee8yamq2k82hq0hl9jpocccpt

JAVA fetched records one by one and call six two procedures (some business logic) for each record.

What I thought was is to change this into PIPELINED fucntion so that as soon as rows returns from SQL its get available for Application to process other two internal procedure..


Chris Saxon
January 12, 2017 - 3:58 pm UTC

Ug, that's quite a SQL query!

A refcursor can return rows "as soon as they're ready". So if you're waiting a long time it's because that's how long the SQL takes to make the rows available.

I'd look at tuning your SQL. To do this you need an execution plan. For instructions on how to get one read:

https://blogs.oracle.com/sql/entry/how_to_create_an_execution

If you need help interpreting the results then post your findings here.

Also: You say you're fetching the results one-by-one in Java. So you've got slow-by-slow processing. I'd look into changing this to use bulk processing. And see if you can run the whole thing in PL/SQL ;)

More to Explore

Security

All of the vital components for a secure database are covered in the Security guide.