Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Jens.

Asked: October 16, 2007 - 11:02 am UTC

Last updated: November 11, 2009 - 3:56 pm UTC

Version: 10.2.0.3

Viewed 10K+ times! This question is

You Asked

Hi,

Our application generates dynamic code for select of fixed set of columns

select c1,  .. cn from tab where cx in ('V1', 'V2', ...) and/or ... ;

the dynamic part is the number in the in 'set'.

We currently do not use bind variables, which of cause bad for query cache, but as the size of the in set can be from 1 .. huge (1000 or more) even use of bind variables will be bad for query cache, caused by different number of bind variables needed.

The 'in set' comes from an external source.

The and/or conditions (dynamic as well) prevnets splitting the statement if correct result should be obtained.

How do we make these type queries with minimal influence on query cache.

Regards
Jens Andersen



and Tom said...

with huge inlists, consider a global temporary table - array insert the values into it, and use a subquery.

Or;

http://asktom.oracle.com/Misc/varying-in-lists.html

Rating

  (7 ratings)

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

Comments

Varying list using a pipelined function

Erick T, October 17, 2007 - 12:43 pm UTC

Instead dynamic code I have been used the joe garrepy string package

http://www.joegarrepy.com/str_package.htm
http://plnet.org/


The use of the piplelined function (split_pipe) is as follows:

Select name
from employees
where employe_id in (SELECT to_number(string_value)
FROM TABLE(str.split_pipe('564,8,76,654,81'),','))


I hope this help you

Regards
Erick

Variable-Sized in Lists

Allan, October 18, 2007 - 8:59 am UTC

Also, for relatively small lists, you can put the values in a nested table, then pass the nested table into the query.

create TYPE t_varchar_1 IS TABLE OF VARCHAR2 (1)
/

DECLARE
nt_test t_varchar_1 := t_varchar_1 ('X', 'Y', 'Z');
BEGIN
FOR r_test IN (SELECT *
FROM DUAL
WHERE dummy IN (select * from table(nt_test))) LOOP
DBMS_OUTPUT.put_line (r_test.dummy);
END LOOP;
END;

Wrong syntax

Erick T, October 18, 2007 - 7:16 pm UTC

/*
This is the right syntax for the previous example
*/

CREATE OR REPLACE
TYPE apps.cust_col_str
AS TABLE OF VARCHAR(1)
/



-- End of DDL Script for Type APPS.CUST_COL_STR


DECLARE a cust_col_str:=cust_col_str('X','y','z');
BEGIN
FOR r_test IN (SELECT *
FROM DUAL
WHERE dummy IN (select * from table(cast (a AS cust_col_str)))) LOOP
DBMS_OUTPUT.put_line ('Found: '||r_test.dummy);
END LOOP;
END;


costing

Connor, October 22, 2007 - 3:05 am UTC

Just be careful with the TABLE() option when it comes to costing. I can't remember off hand, but Oracle assumes something like 8k rows coming back from the TABLE() which might impact your plans.

hth
connor
Tom Kyte
October 23, 2007 - 1:35 pm UTC

function of the block size actually... the default number of rows is...

http://docs.oracle.com/docs/cd/B10501_01/server.920/a96533/stats.htm#25056

Also: consider the cardinality hint

Stew Ashton, October 23, 2007 - 4:40 pm UTC


With this hint you can tell the optimizer how many rows to expect from a query or subquery when statistics are unavailable.

Might be useful with the global temporary table, or with the "varying in list" solution:

http://asktom.oracle.com/~tkyte/cardinality.html

Helena Marková, October 24, 2007 - 3:42 am UTC


cardinality

Tom, November 10, 2009 - 2:39 pm UTC

I have seen links to the page Mr. Ashton mentions above from other replies you have on the site as well as from one of your Oracle Magazine articles ( https://asktom.oracle.com/Misc/oramag/on-fetching-storing-and-indexing.html ), but I cannot find it in the files section of the site and the link returns a 404. Could you point me to it? Thanks.