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

Home -> Community -> Usenet -> c.d.o.tools -> Re: Parameters in view

Re: Parameters in view

From: Thomas Kyte <tkyte_at_us.oracle.com>
Date: 2 Jul 2001 08:29:21 -0700
Message-ID: <9hq40h02n03@drn.newsguy.com>

In article <9hq1r3$k1u$1_at_rex.ip-plus.net>, "Ian says...
>
>Thomas,
>
>I've just run a litt test on the calling of a function:
>
>I added a counter to the get_myvar function to note how many times it had
>been called, then included a second function to return the number of calls
>to the get_myvar function. What happens is intereting. When I select the
>function from Dual, the counter is incremented by 1, as expected. However
>when I add it to a larger query (14,000 records) the function is called
>TWICE, not once per row. The result is that I can still wrap the context
>management in my own package, while keeping the efficiency of the calls.
>
>I haven't found the details in the manual, but my guess is that the second
>call would check for differences before binding the result to the view.
>
>Any ideas?
>

DUAL is magical -- its special.

It all depends on how the optimizer does the plan. Consider:

ops$tkyte_at_ORA817.US.ORACLE.COM> create or replace package my_pkg   2 as
  3 cnt number;
  4 end;
  5 /
Package created.

ops$tkyte_at_ORA817.US.ORACLE.COM> create or replace function foo return number   2 as
  3 begin
  4 my_pkg.cnt := my_pkg.cnt + 1;   5
  6 return 0;
  7 end;
  8 /
Function created.

ops$tkyte_at_ORA817.US.ORACLE.COM> exec my_pkg.cnt := 0 PL/SQL procedure successfully completed.

ops$tkyte_at_ORA817.US.ORACLE.COM> select count(*) from all_objects where object_id = foo;

  COUNT(*)


         0

ops$tkyte_at_ORA817.US.ORACLE.COM> exec dbms_output.put_line( my_pkg.cnt ); 2

PL/SQL procedure successfully completed.

There is used the index so Oracle evaluated the function AND THEN went to the index. However:

ops$tkyte_at_ORA817.US.ORACLE.COM> exec my_pkg.cnt := 0

PL/SQL procedure successfully completed.

ops$tkyte_at_ORA817.US.ORACLE.COM> select count(*) from all_objects where object_id+0 = foo;

  COUNT(*)


         0

ops$tkyte_at_ORA817.US.ORACLE.COM> exec dbms_output.put_line( my_pkg.cnt ); 27759

PL/SQL procedure successfully completed.

ops$tkyte_at_ORA817.US.ORACLE.COM>

There is did it once per row in the query. As I said "it might" -- i would not suggest using this approach in Oracle8i and up as it totally depends on the query plan as to how many times foo will be called.

A trick that "usually" works is:

ops$tkyte_at_ORA817.US.ORACLE.COM> exec my_pkg.cnt := 0

PL/SQL procedure successfully completed.

ops$tkyte_at_ORA817.US.ORACLE.COM> select count(*) from all_objects where object_id+0 = (select foo+rownum-1 from dual );

  COUNT(*)


         0

ops$tkyte_at_ORA817.US.ORACLE.COM> exec dbms_output.put_line( my_pkg.cnt ); 1

PL/SQL procedure successfully completed.

there I used rownum in the subquery which should force the subquery to be resolved off to the side in a temporary table, avoiding the call to FOO every time.

Again, sys_context would be better.

>
>"Thomas Kyte" <tkyte_at_us.oracle.com> wrote in message
>news:9hptqu01ph9_at_drn.newsguy.com...
>> In article <9hp9ge$fg7$1_at_rex.ip-plus.net>, "Ian says...
>> >
>> >Another way is to put all your context variables into a package with
>> >procedures to set the variables and a function to return it. The
 advantage
>> >of this is if there is anything you need to do following the setting of
 the
>> >variable you can hide it from the calling program. For example you can
>> >execute a procedure with will insert a result set into a temporary table
 and
>> >then browse on that.
>> >
>>
>> You can do this, but beware -- Oracle might invoke your function ONCE PER
 ROW of
>> the query -- not once per query.
>>
>> SYS_CONTEXT and an application context would be infinitely preferable to
 this
>> method and much much more performant. SYS_CONTEXT is treated like a bind
>> variable and invoked once per query -- not once per row per query.
>>
>>
>> >Here's the code:
>> >/* Begin create Package */
>> >
>> >CREATE
>> >PACKAGE tpms.context_package
>> >IS
>> > PROCEDURE set_myvar (p_myvar IN NUMBER);
>> >
>> > FUNCTION get_myvar
>> > RETURN NUMBER;
>> >
>> > PRAGMA RESTRICT_REFERENCES (get_myvar, WNDS, WNPS);
>> >END;
>> >/
>> >
>> >CREATE
>> >PACKAGE BODY tpms.context_package
>> >IS
>> > v_myvar NUMBER;
>> >
>> > PROCEDURE set_myvar (p_myvar IN NUMBER)
>> > IS
>> > BEGIN
>> > v_myvar := p_myvar;
>> > END;
>> >
>> > FUNCTION get_myvar
>> > RETURN NUMBER
>> > IS
>> > BEGIN
>> > RETURN v_myvar;
>> > END;
>> >END;
>> >/
>> >
>> >/* End create Package */
>> >
>> >/* Begin set Variable */
>> >
>> >BEGIN
>> > context_package.set_myvar (1);
>> > COMMIT;
>> >END;
>> >
>> >/* End set Variable */
>> >
>> >/* Begin get Variable */
>> >
>> >SELECT context_package.get_myvar
>> >FROM dual
>> >
>> >/* End get Variable */
>> >
>> >
>> >"Thomas Kyte" <tkyte_at_us.oracle.com> wrote in message
>> >news:9hoitm0486_at_drn.newsguy.com...
>> >> In article <fDN%6.149236$qM3.18028774_at_news.soneraplaza.nl>, "Julian
 says...
>> >> >
>> >> >Hi,
>> >> >
>> >> >I am having a big problem with Oracle. We use WebDB in our company to
 make
>> >> >reports. Now the queries in WebDB can't be that large, so I created a
 view
>> >> >for a big query. Now the query takes way too long to execute, because
 a
 view
>> >> >fetches its results first and then webdb filters the date (with
 parameters).
>> >> >Because it takes too long webdb generetes a time-out and customers
 don't
 see
>> >> >results.
>> >> >
>> >> >If I use the source of the view as a query and give as a parameter for
>> >> >example customer_id = 2 than the query is very fast. It would be nice,
 or
>> >> >essential to have parameters within the view itself. But is that
 possible?
>> >> >Or are there any other ways to do this?
>> >> >
>> >> >Please help!!!!
>> >> >
>> >> >Julian Kooiker
>> >> >
>> >> >
>> >>
>> >>
>> >> Sure, depends in your version, but I'll cover a couple of ways....
>> >>
>> >>
>> >> First and easiest for a single parameter is
>> >> dbms_application_info.set_client_info. Consider:
>> >>
>> >> scott_at_TKYTE816> create or replace view emp_v
>> >> 2 as
>> >> 3 select ename, empno
>> >> 4 from emp
>> >> 5 where ename like userenv( 'client_info' )
>> >> 6 /
>> >>
>> >> View created.
>> >>
>> >> scott_at_TKYTE816> select * from emp_v;
>> >> no rows selected
>> >>
>> >> scott_at_TKYTE816> exec dbms_application_info.set_client_info( 'K%' )
>> >> PL/SQL procedure successfully completed.
>> >>
>> >> scott_at_TKYTE816> select * from emp_v;
>> >>
>> >> ENAME EMPNO
>> >> ---------- ----------
>> >> KING 7839
>> >>
>> >>
>> >> userenv('client_info') returns whatever you stuffed into it via
 set_client_info.
>> >> In a before page or report plsql block, you can set the parameter
 (using
 substr
>> >> on userenv, you could set more then one).
>> >>
>> >> A more sophisticated method is an APPLICATION CONTEXT, this is 8i or up
 (no one
>> >> EVER seems to post their version, never):
>> >>
>> >> scott_at_TKYTE816> create or replace context my_context using my_procedure
>> >> 2 /
>> >> Context created.
>> >>
>> >> scott_at_TKYTE816>
>> >> scott_at_TKYTE816> create or replace procedure my_procedure( p_name in
 varchar2,
>> >> p_val in varchar2 )
>> >> 2 as
>> >> 3 begin
>> >> 4 dbms_session.set_context( 'my_context', p_name, p_val );
>> >> 5 end;
>> >> 6 /
>> >>
>> >> Procedure created.
>> >>
>> >> scott_at_TKYTE816> create or replace view emp_v
>> >> 2 as
>> >> 3 select ename, empno
>> >> 4 from emp
>> >> 5 where ename like sys_context( 'my_context', 'ename_like' )
>> >> 6 OR empno = to_number( sys_context( 'my_context', 'empno' ) )
>> >> 7 /
>> >>
>> >> View created.
>> >>
>> >> scott_at_TKYTE816> select * from emp_v;
>> >> no rows selected
>> >>
>> >> scott_at_TKYTE816> exec my_procedure( 'empno', 7654 )
>> >>
>> >> PL/SQL procedure successfully completed.
>> >>
>> >> scott_at_TKYTE816> select * from emp_v;
>> >>
>> >> ENAME EMPNO
>> >> ---------- ----------
>> >> MARTIN 7654
>> >>
>> >> scott_at_TKYTE816> exec my_procedure( 'empno', null )
>> >>
>> >> PL/SQL procedure successfully completed.
>> >>
>> >> scott_at_TKYTE816> exec my_procedure( 'ename_like', 'A%' )
>> >>
>> >> PL/SQL procedure successfully completed.
>> >>
>> >> scott_at_TKYTE816> select * from emp_v;
>> >>
>> >> ENAME EMPNO
>> >> ---------- ----------
>> >> ADAMS 7876
>> >> ALLEN 7499
>> >>
>> >> --
>> >> Thomas Kyte (tkyte@us.oracle.com) http://asktom.oracle.com/
>> >> Expert one on one Oracle, programming techniques and solutions for
 Oracle.
>> >> http://www.amazon.com/exec/obidos/ASIN/1861004826/
>> >> Opinions are mine and do not necessarily reflect those of Oracle Corp
>> >>
>> >
>> >
>>
>> --
>> Thomas Kyte (tkyte@us.oracle.com) http://asktom.oracle.com/
>> Expert one on one Oracle, programming techniques and solutions for Oracle.
>> http://www.amazon.com/exec/obidos/ASIN/1861004826/
>> Opinions are mine and do not necessarily reflect those of Oracle Corp
>>
>
>

--
Thomas Kyte (tkyte@us.oracle.com)             http://asktom.oracle.com/ 
Expert one on one Oracle, programming techniques and solutions for Oracle.
http://www.amazon.com/exec/obidos/ASIN/1861004826/  
Opinions are mine and do not necessarily reflect those of Oracle Corp 
Received on Mon Jul 02 2001 - 10:29:21 CDT

Original text of this message

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