Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, gaurang.

Asked: March 31, 2002 - 6:30 pm UTC

Last updated: April 22, 2013 - 7:18 pm UTC

Version: 8.1.7

Viewed 10K+ times! This question is

You Asked

Hi TOM,

I am loding 500000 rows into an array. and search that array like table e.g

select * into value from TABLE(cast(tabls as mytable))
where column_name = ....

It is very slow process. Is there any way to create index of array in memory and speed up operation.

We have lots of RAM so memory is not problem.

Thanks.





and Tom said...

Why would you do that?

Don't do that. Use a REAL table (don't load them up in the first place). If the "real" table is too burdensome to query -- use a indexed global temporary table.

In 9iR2 there will be associative arrays -- where the index can be a string instead of just a number.

Alternatively, if you have my book -- i demonstrate how to setup a hash table today in Oracle8.0 and up easily. If you select "where column_name = :value", then all you need really is a hash table in your array instead of an array indexed by a sequential number.

I think you might be utterly surprised at the amount of ram taken by your array as well.

Rating

  (5 ratings)

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

Comments

A reader, August 06, 2002 - 9:42 am UTC

Hi Tom,

 Finally we got oracle 9i in our company.
 We have 9i R2.

 I am testing associative array and BULK COLLECT feature    together.


 ORGANIZATION_NAME                         NOT NULL VARCHAR2(110)

 I am getting errors

  1   declare
  2   type t_org  is table of varchar2(110) index by varchar2(110);
  3   t_org_arr     t_org;
  4   BEGIN
  5      select organization_name BULK COLLECT INTO t_org_arr
  6        from pubs.olv@renpqa1.world@pubs_link
  7      where delete_indicator = 0
  8         and main_point_flag ='Y';
  9       dbms_output.put_line('Oraganization :'||t_org_arr('Baker Rost'));
 10       dbms_output.put_line('Total :'||t_org_arr.count);
 11*  end;
SQL> /
    select organization_name BULK COLLECT INTO t_org_arr
                                               *
ERROR at line 5:
ORA-06550: line 5, column 48:
PLS-00657: Implementation restriction: bulk SQL with associative arrays with VARCHAR2 key is not sup
ORA-06550: line 5, column 48:
PLS-00597: expression 'T_ORG_ARR' in the INTO list is of wrong type
ORA-06550: line 6, column 7:
PL/SQL: ORA-00904: : invalid identifier
ORA-06550: line 5, column 5:
PL/SQL: SQL Statement ignored

--Can you tell me where it is wrong?

-- In oracle 8i BULK COLLECT accross database link was not supported.Is it supported in ORACLE 9i?

-- Above error tells that associative array is not supported with BULK COLLECT.
  Can you explain why it is not supported?.
  
  If it support bulk collect then populating array and   seraching array would be the BEST.

 Thanks,

  

Tom Kyte
August 07, 2002 - 10:03 am UTC

I believe the error message itself is very telling:

PLS-00657: Implementation restriction: bulk SQL with associative arrays with
VARCHAR2 key is not supported

don't you??

Think about it -- look at your SQL, what *should* happen in your mind with the above bulk collect? I mean -- what should the "index" in the array be? With an index by binary_integer -- it is logical that row 1 goes into index 1, row 2 into index 2 and so on. With an index by varchar2 -- when you fetch organization name -- what INDEX should be used?????

Look at your example and tell me what would/should be returned by

t_org_arr( 'Baker Rost' )

How would we know to use the string 'Baker Rost' as a subscript??


Here is how you would do this:

scott@ORA920.LOCALHOST> declare
2 type temp is table of varchar2(110) index by binary_integer;
3
4 l_key temp;
5 l_val temp;
6
7 type t_org is table of varchar2(110) index by varchar2(110);
8 t_org_arr t_org;
9 BEGIN
10 select username, created BULK COLLECT INTO l_key, l_val
11 from all_users@ora920.us.oracle.com;
12
13 for i in 1 .. l_key.count
14 loop
15 t_org_arr( l_key(i) ) := l_val(i);
16 end loop;
17
18 dbms_output.put_line('Created : '||t_org_arr('SCOTT'));
19 dbms_output.put_line('Total : '||t_org_arr.count);
20 end;
21 /
Created : 13-MAY-02
Total : 34

PL/SQL procedure successfully completed.


You'll bulk collect the KEYs (indexes, subscripts) and the VALs. You can do this over a dblink as shown. You would then put them into the associated array.



Very interesting

A reader, August 07, 2002 - 11:51 am UTC


2-column collection INTO 2-level associative array using BULK

Jan, June 12, 2003 - 6:06 am UTC

I have collection:
----------------------
CREATE TYPE my_rec_type AS OBJECT(
val_name VARCHAR2(10),
val VARCHAR2(30));

CREATE TYPE my_list_type AS TABLE OF my_rec_type;
-----------------------
my_list have data like:

my_list(1) = ('AGE','10');
my_list(2) = ('AGE','15');
my_list(3) = ('GENDER','M');
...

And I want to assign these data into 2-level associative array in PL/SQL using a single statement (no LOOP - this I know)


-------------------------
TYPE ty_my_val IS TABLE OF VARCHAR2(30) INDEX BY BINARY_INTEGER;
TYPE ty_my_indexed_list IS TABLE OF ty_my_val INDEX BY VARCHAR2(10);
-------------------------

So the result will be:

my_indexed_list('AGE')(1) = '10'
my_indexed_list('AGE')(2) = '15'
my_indexed_list('GENDER')(1) = 'M'
...

Is it possible to do it in the way like (pseudocode) :

SELECT my_list(name,val) BULK COLLECT
INTO my_indexed_list(index,val)
from TABLE(CAST(my_list...

Thanks.




Hash Table - For Pattern Matching

Shravani, July 27, 2011 - 7:27 am UTC

Hi Tom,

This is regarding the first question of this thread. I referred your book "Expert One On One Oracle" for the effective use of Hash Table. However I am
not clear whether I can use it for below requirement.

As a daily process, we are loading a inventory files which gives item with its unit. I am giving the dummy tables just for example purposes

The table structure is

create table item_details
(
stock_id number,
item_list varchar2(4000),
scheme_id varchar2(4000)
);

and records are

insert into item_details (stock_id, item_list) values (10, 'books,pen,pencil');
insert into item_details (stock_id, item_list) values (20, 'pen');
insert into item_details (stock_id, item_list) values (30, 'books,pencil');
insert into item_details (stock_id, item_list) values (40, 'books,pen');
insert into item_details (stock_id, item_list) values (50, 'books');
insert into item_details (stock_id, item_list) values (60, 'pencil');
insert into item_details (stock_id, item_list) values (70, 'cd-set,computer books,keyboard.monitor,mouse-pad,pen-drive');
insert into item_details (stock_id, item_list) values (80, 'books,keyboard.monitor,pen');
insert into item_details (stock_id, item_list) values (90, 'brush,paper,pen');
insert into item_details (stock_id, item_list) values (100, 'brush,pen');
commit;

Note - The Item List is always sorted alphabetically.

We have a set process to load this file on monthly basis and then transform the data into main tables.

As per new requirement, we will also get one more file which will have item lists and scheme code. We have designed below table


create table scheme_details
(
scheme_id number,
item_list varchar2(2000)
);

insert into scheme_details values (1, 'cd-set,pen,softwares,keyboard');
insert into scheme_details values (2, 'pencil,pen,books');
insert into scheme_details values (3, 'computer book,keyboard,mouse-pad,pen,pencil');
commit;

Now the requirement is to check the "item_list" from "scheme_details" and if any one item is matched with the "item_details.list" then append the
scheme id.

After the process records in "item_details" should be

STOCK_ID ITEM_LIST SCHEME_ID
-----------------------------------------------------------------------------------------------------------------
10 'books,pen,pencil' 1,2,3
20 'pen' 1,2,3
30 'books,pencil' 2,3
40 'books,pen' 1,2,3
50 'books' 2
60 'pencil' 3
70 'cd-set,computer books,keyboard.monitor,mouse-pad,pen-drive' 1,3
80 'books,keyboard.monitor,pen' 1,2,3
90 'brush,paper,pen' 1,2,3
100 'brush,pen' 1,2,3

The current number rows in "item_details" is > 1.2 M. And the estimated number of records in new "scheme_details" is around 50-60K.

We tried using the direct UPDATE but it is taking lot of time.

Can we use the hash-table for the pattern comparison? Can you please provide just the effectice PL-SQL design for such requirements?

Regards
Shravani
Tom Kyte
July 28, 2011 - 7:04 pm UTC

i hate your schema, i truly do.

what kind of person stores a delimited list? why? do you really really just want the most horrifically bad performance you can ever achieve? do you love writing lots of complex code to parse strings?

My answer would involve a redesign (no wait, it would involve an INITIAL design) and the delimited lists would disappear. Sorry, I have no magic for this, it is going to be painful.

index by varchar2

Dinakar, April 15, 2013 - 5:19 pm UTC

Hi,
When we use a collection of index by varchar2, is there a way to apply like clause rather than exists clause to check for an existance of an index.

eg:
DECLARE
TYPE T1 IS TABLE OF VARCHAR2(5) INDEX BY VARCHAR2(50);
T2 T1;
BEGIN
T2('INSTR-COUNTRY-DOM-US'):='US';
T2('INSTR-COUNTRY-INCORP-US'):='IN';
END;

Now, the requirement is to check for an index like 'INSTR-COUNTRY-INCORP%'. if there is one then thats what the code should reurn 'IN'. How to achieve this?
Tom Kyte
April 22, 2013 - 7:18 pm UTC

you cannot use an index by table in that fashion. you would have to procedurally loop over the values and apply like to each index in turn.