tags:

views:

78

answers:

2

Hello everybody,

I'm working on a piece of sql that I want to optimize. I have inside a bunch of cursors. I'm wondering if I can use something else instead of cursors. I'm thinking using some kind of variables, filling them, and for the rest of the treatment avoiding the DB connection (I have a complex treatment).

For instance I have a piece of code like :

TYPE rec_basket IS RECORD (
 FIELD1 VARCHAR2(40),
 FIELD2 NUMBER(10),
 FIELD3 VARCHAR2(6)
 );

 TYPE tab_basket IS TABLE OF rec_basket
 INDEX BY BINARY_INTEGER;

........................

CURSOR cur_baskets
   IS
select * from toto

............................

 FOR i IN cur_baskets
   LOOP
  l_tab_basket (l_nbasket).field1 := i.field1;
  l_tab_basket (l_nbasket).field2 := i.field2;
  l_tab_basket (l_nbasket).field3  := i.field3;
  l_nbasket := l_nbasket + 1;    
   END LOOP;

Using a cursor and filling the l_tab_basket variable is the best way to go? I'm using l_tab_basket (index) somewhere in my code. The reason I've put this piece of code is that I would like use this mechanism for my other cursors. Actually I have a cursor inside another one. And for each line of each of them I have some treatment. I would like to replace the cursors with something else, but I don't know how. Thanks.

+2  A: 

Hi CC,

You can use BULK COLLECT to fetch all records into your nested table. This would work in 10g+:

SQL> DECLARE
  2     TYPE rec_basket IS RECORD(
  3        field1 VARCHAR2(40),
  4        field2 NUMBER(10),
  5        field3 VARCHAR2(6));
  6     TYPE tab_basket IS TABLE OF rec_basket INDEX BY BINARY_INTEGER;
  7     l_tab_basket tab_basket;
  8  BEGIN
  9     SELECT 'a', ROWNUM, 'b'
 10       BULK COLLECT INTO l_tab_basket
 11       FROM dual CONNECT BY LEVEL <= 1000;
 12  END;
 13  /

PL/SQL procedure successfully completed

Keep in mind that Oracle 10g automatically fetch records from implicit cursors in bulk (100) in pl/sql, so the gains should be marginal at best: you will probably spend more time querying the DB than building the array unless the array is really really big (and in that case is it wise to use a nested table?)

Vincent Malgrat
I thought that Oracle only did "fetch-ahead" for implicit cursors
OMG Ponies
What I need is to be able to retrieve one by one the lines from my tab_basket. How can I do that?
CC
@CC - why do you think you need to retrieve the records one by one? Set processing is definitely the most optimal way of working with data. You really need to give us more details. Help us to help you.
APC
I don't THINK I need the retrieve the records one by one, I just need it. I have some stuff to to with each line. And I have a cursor inside another one. I'm just trying to find the best solution to optimize this stuff.
CC
@OMG Ponies: You're right :) see http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1205168148688#43635060217187 . Implicit cursors are almost always preferable to explicit ones, in particular because they are more optimized by Oracle. I don't know if recent versions have changed this behaviour but I've just checked with 10.2.0.3 and only the implicit cursors fetch ahead.
Vincent Malgrat
Cool - Thx Vincent
OMG Ponies
+1  A: 

Logic of your code is not very clear. You have not written whole program. Let us examine:

CURSOR cur_baskets IS select * from toto

Here the value are read from the table toto and put into a cursor.

In the following lines the values are read from the cursor and put into l_tab_basket.

FOR i IN cur_baskets LOOP l_tab_basket (l_nbasket).field1 := i.field1; l_tab_basket (l_nbasket).field2 := i.field2; l_tab_basket (l_nbasket).field3 := i.field3; l_nbasket := l_nbasket + 1;
END LOOP;

So same values are going to local variable twice. This can be avoided. You can find out ways to directly insert into or update target table.

You can try bulk collect. If toto is small, you can insert into or update the target table without using cursor.

Vishnu Gupta
Actually, I'm using l_tab_basket because,I need to recover the data many times (because this part is inside another cursor), so to avoid doing the query many times. I have 2 cursors (one inside another). The inner one has 50 items and the outside one has 2000 items.
CC
Since the inner one will be executed for each iteration of the outside one, I'm using the TABLE_OF to put the values into a variable.
CC
Thanks for the INSERT BULK idea. I did the job.
CC
@CC You are welcome. I am grateful to you for your compliments and comments.
Vishnu Gupta