Skip to Main Content

SQL & PL/SQL

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Query not using index

Laurent SchneiderSep 19 2008 — edited Sep 22 2008
Hi,
I am wondering if there is a way to make my query use an index without specifying the INDEX hint.

Thanks
Laurent

PS: I am using 9.2.0.8
SQL> create table lsc_t1(a number primary key, b number);

Table created.

SQL> create table lsc_t2(a number primary key, b number);

Table created.

SQL> create table lsc_t3(a number primary key, b number);

Table created.

SQL> insert into lsc_t1(a,b) select rownum, dbms_random.value from dual connect by level<10000;

9999 rows created.

SQL> insert into lsc_t2(a,b) select rownum, dbms_random.value from dual connect by level<1000;

999 rows created.

SQL> insert into lsc_t3(a,b) select rownum, dbms_random.value from dual connect by level<1000;

999 rows created.

SQL> commit;

Commit complete.

SQL> begin
  2    dbms_stats.gather_table_stats(user,'LSC_T1');
  3    dbms_stats.gather_table_stats(user,'LSC_T2');
  4    dbms_stats.gather_table_stats(user,'LSC_T3');
  5  end;
  6  /

PL/SQL procedure successfully completed.

SQL> set timi on
SQL> select --+ INDEX(lsc_t1)
  2    * from lsc_t1
  3  where a in (select a from lsc_t2 where b<.01 union all select a from lsc_t3 where b<.01);

         A          B
---------- ----------
       140 .138460932
       161 .928661302
       281 .830010122
       440 .071851157
       443 .355640404
       516 .791276412
       598 .508219846
       600 .158621147
       643 .748363911
       747 .777346635
       836 .390349029
       869 .292453677
       874 .914353702
       881 .930301092

14 rows selected.

Elapsed: 00:00:00.03
SQL> select
  2    * from lsc_t1
  3  where a in (select a from lsc_t2 where b<.01 union all select a from lsc_t3 where b<.01);

         A          B
---------- ----------
       140 .138460932
       161 .928661302
       281 .830010122
       440 .071851157
       443 .355640404
       516 .791276412
       598 .508219846
       600 .158621147
       643 .748363911
       747 .777346635
       836 .390349029
       869 .292453677
       874 .914353702
       881 .930301092

14 rows selected.

Elapsed: 00:00:00.26
SQL> set timi off autot trace exp
SQL> select --+ INDEX(lsc_t1)
  2    * from lsc_t1
  3  where a in (select a from lsc_t2 where b<.01 union all select a from lsc_t3 where b<.01);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=19 Card=17 Bytes=476)
   1    0   NESTED LOOPS (Cost=19 Card=17 Bytes=476)
   2    1     VIEW OF 'VW_NSO_1' (Cost=2 Card=17 Bytes=68)
   3    2       SORT (UNIQUE)
   4    3         UNION-ALL
   5    4           TABLE ACCESS (FULL) OF 'LSC_T2' (Cost=2 Card=9 Bytes=216)
   6    4           TABLE ACCESS (FULL) OF 'LSC_T3' (Cost=2 Card=8 Bytes=192)
   7    1     TABLE ACCESS (BY INDEX ROWID) OF 'LSC_T1' (Cost=1 Card=1 Bytes=24)
   8    7       INDEX (UNIQUE SCAN) OF 'SYS_C001186489' (UNIQUE)



SQL> select
  2    * from lsc_t1
  3  where a in (select a from lsc_t2 where b<.01 union all select a from lsc_t3 where b<.01);

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=6 Card=17 Bytes=476)
   1    0   NESTED LOOPS (Cost=6 Card=17 Bytes=476)
   2    1     TABLE ACCESS (FULL) OF 'LSC_T1' (Cost=6 Card=9999 Bytes=239976)
   3    1     VIEW OF 'VW_NSO_1'
   4    3       SORT (UNIQUE)
   5    4         UNION-ALL (PARTITION)
   6    5           TABLE ACCESS (BY INDEX ROWID) OF 'LSC_T2' (Cost=2 Card=1 Bytes=24)
   7    6             INDEX (UNIQUE SCAN) OF 'SYS_C001186490' (UNIQUE) (Cost=1 Card=1)
   8    5           TABLE ACCESS (BY INDEX ROWID) OF 'LSC_T3' (Cost=2 Card=1 Bytes=24)
   9    8             INDEX (UNIQUE SCAN) OF 'SYS_C001186491' (UNIQUE) (Cost=1 Card=1)
This post has been answered by Randolf Geist on Sep 22 2008
Jump to Answer

Comments

odie_63
PS: I don't want to use an hardcoding
Why?

Do you have such a scenario that you don't know the procedure name you're trying to compile?

Edited by: odie_63 on 11 janv. 2013 10:45
padders
Simple answer is you can't - without generating some additional metadata for the package.

One way to generate the metadata would appear to be PL/Scope in 11g but I haven't actually tried that to see how it pans out.
odie_63
There's $$PLSQL_UNIT compiler directive but it doesn't reference subprograms in a package, only the package itself :
SQL> create or replace package mypck is
  2    procedure myprc;
  3  end;
  4  /
 
Package created
 
SQL> 
SQL> create or replace package body mypck is
  2    procedure myprc is
  3    begin
  4      dbms_output.put_line('I''m in '||$$PLSQL_UNIT);
  5    end;
  6  end;
  7  /
 
Package body created
 
SQL> exec mypck.myprc;
 
I'm in MYPCK
 
PL/SQL procedure successfully completed
 
bencol
This might help you understand the problem:
http://tkyte.blogspot.co.uk/2009/10/httpasktomoraclecomtkytewhocalledme.html

Buit I usually hardcode the proc name into a variable and use that for logging.
unknown-7404
You've posted enough to know that you need to provide your 4 digit Oracle version (result of SELECT * FROM V$VERSION).
>
is it possible to obtain a called procedure/function name within package?

For a measuring and tracing purpose, I would like to store an info at the beginning of each procedure/function in package with timestamp + additional details if needed.
>
I usually use this method

1. Create a SQL type for logging information
2. Put the package name into a constant in the package spec
3. Add a line to each procedure/function for the name.

Sample package spec
	/******************************************************************************
	 * Constants and package variables
	 ******************************************************************************/
		gc_pk_name			CONSTANT VARCHAR2(30) := 'PK_TEST';
Sample procedure code in package
	 PROCEDURE P_TEST_INIT
	 IS
	   c_proc_name CONSTANT VARCHAR2(80)  := 'P_TEST_INIT';
	   v_log_info  TYPE_LOG_INFO := TYPE_LOG_INFO(gc_pk_name, c_proc_name); -- create the log type instance

	 BEGIN
		NULL; -- code goes here
	 EXCEPTION
	 WHEN ??? THEN
		v_log_info.log_code := SQLCODE;  -- add info to the log type
		v_log_info.log_message := SQLERRM;
		v_log_info.log_time    := SYSDATE;
		pk_log.p_log_error(v_log_info);
                                raise;
	 END P_PK_TEST_INIT;
Sample SQL type
DROP TYPE TYPE_LOG_INFO;

CREATE OR REPLACE TYPE TYPE_LOG_INFO AUTHID DEFINER AS OBJECT (
/* *****************************************************************************
 *  NAME:      TYPE_LOG_INFO
 *  PURPOSE:   Holds info used by PK_LOG package to log errors.
 *
 *             Using a TYPE instance keeps the procedures and functions
 *             independent of the logging mechanism.
 *
 *             If new logging features are needed a SUB TYPE can be derived
 *             from this base type to add the new functionality without
 *             breaking any existing code.
 *
 *  REVISIONS:
 *  Ver        Date        Author           Description
 *
 *   1.00      mm/dd/yyyy  me               Initial Version.
 ******************************************************************************/
    PACKAGE_NAME  VARCHAR2(80),
    PROC_NAME     VARCHAR2(80),
    STEP_NUMBER   NUMBER,
    LOG_LEVEL   VARCHAR2(10),
    LOG_CODE    NUMBER,
    LOG_MESSAGE VARCHAR2(1024),
    LOG_TIME    TIMESTAMP,
    CONSTRUCTOR FUNCTION type_log_info (p_package_name IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_proc_name IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_step_number IN NUMBER DEFAULT 1,
                                        p_LOG_level IN VARCHAR2 DEFAULT 'Uninit',
                                        p_LOG_code IN NUMBER DEFAULT -1,
                                        p_LOG_message IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_LOG_time IN DATE DEFAULT SYSDATE)
                RETURN SELF AS RESULT
  ) NOT FINAL;
/

DROP TYPE BODY TYPE_LOG_INFO;

CREATE OR REPLACE TYPE BODY TYPE_LOG_INFO IS
    CONSTRUCTOR FUNCTION type_log_info (p_package_name IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_proc_name IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_step_number IN NUMBER DEFAULT 1,
                                        p_LOG_level IN VARCHAR2 DEFAULT 'Uninit',
                                        p_LOG_code IN NUMBER DEFAULT -1,
                                        p_LOG_message IN VARCHAR2 DEFAULT 'Uninitialized',
                                        p_LOG_time IN DATE DEFAULT SYSDATE)
     RETURN SELF AS RESULT IS
    BEGIN
      self.package_name  := p_package_name;
      self.proc_name     := p_proc_name;
      self.step_number   := p_step_number;
      self.LOG_level   := p_LOG_level;
      self.LOG_code    := p_LOG_code;
      self.LOG_message := p_LOG_message;
      self.LOG_time    := p_LOG_time;
      RETURN;
    END;
END;
/
SHO ERR
Edited by: rp0428 on Jan 11, 2013 10:35 AM after 1st cup of coffee ;)
odie_63
rp0428 wrote:
You would want the $$PLSQL_UNIT directive.
And as shown in my post, this doesn't apply to subprograms in a package, which seems to be precisely what OP is after.
unknown-7404
Thanks - brain f*** - didn't even see your post somehow. I update my post with the old method.
1 - 7
Locked Post
New comments cannot be posted to this locked post.

Post Details

Locked on Oct 20 2008
Added on Sep 19 2008
8 comments
620 views