Skip to Main Content
  • Questions
  • The different values of the OPTIMIZER_MODE column in V$SQLAREA

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Renauld.

Asked: August 24, 2000 - 8:36 am UTC

Last updated: March 14, 2007 - 2:01 pm UTC

Version: version 8.0.5

Viewed 1000+ times

You Asked

Hi Tom,

I was looking at the V$SQLAREA table when I saw
"MULTIPLE CHILDREN PRESENT" in the OPTIMIZER_MODE
column.

I spent sometimes through the doc and the net
but have not find any kind of explaination.

Could you give a word on this ? and perhaps
a good place to read through.

Regards
Renauld Chapellier

and Tom said...


Finding this value in optimizer_mode column of v$sql means that the same query was executed at least twice with a slightly different executing environment which caused the optimizer to choose a different execution path.

Some examples:

- Two people selecting from different private tables named emp.

- Same query but are using different session optimizer_mode
setting.

- Both queries are using cost based, but with a different
session value for sort_area_size or other CBO related
parameters.


Rating

  (8 ratings)

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

Comments

What CBO settings can affect the sharable cursors

Juli, September 21, 2005 - 11:08 pm UTC

Hi Tom,

One of our application generates a lot of child cursors for the same sql. I checked the view v$sql_shared_cursor and could not find out any 'Y' value for any of them. So, what else can stop them from sharing? Can you please list some of the settings. Also, I can see over 1000 such cursors from v$sql, but can only a handfull of them from v$sql_shared_cursor. What's the reason making those child cursors disappear from the view?

Thank you for your time.


Tom Kyte
September 22, 2005 - 1:27 pm UTC

can you reproduce this by taking one of these sql's and just running it in sqlplus using different sessions/binds?

version, example query, the table creates, and sample bind values would be good.

cursor sharing being used here?

more info related listed below

Julie, September 23, 2005 - 10:13 pm UTC

Thanks Tom. Here is an example got from v$sqlarea:

SQL_TEXT (not complete):

SELECT UNIQUE S.MM_ID, S.MM_N, S.MM_NM, S.MM_MKT_STUS_C, S.MM_ACCT_TYP_C, S.MM_CTL_PL_ID, S.MM_EFF_FRM_DT,
K.MM_TYP_C, CL_RO_IN, DECODE(K.MM_TYP_C, :"SYS_B_00", DECODE(SCHM.SCHM_CVT_IN, NULL, :"SYS_B_01",
SCHM.SCHM_CVT_IN), :"SYS_B_02", DECODE(SCHM.SCHM_CVT_IN, NULL, :"SYS_B_03", SCHM.SCHM_CVT_IN),
:"SYS_B_04", DECODE(SCHM.SCHM_CVT_IN, NULL, :"SYS_B_05", SCHM.SCHM_CVT_IN), :"SYS_B_06",
DECODE(SCHM.SCHM_CVT_IN, NULL, :"SYS_B_07", SCHM.SCHM_CVT_IN), :"SYS_B_08", DECODE(SCHM.SCHM_ACT_IN, NULL,
:"SYS_B_09", SCHM.SCHM_ACVT_IN), :"SYS_B_10") acting_indicator, S.MM_HPS_MGRTD_IN, MM_CTR_OF_IN
FROM SCH S, KEL K, SCHM
WHERE (K.MM_ID = S.MM_ID)
AND S.MM_EFF_FRM_DT = (SELECT MAX( S1.MM_EFF_FRM_DT )
FROM SCH S1 WHERE


SHARABLE_MEM PERSISTENT_MEM RUNTIME_MEM SORTS VERSION_COUNT LOADED_VERSIONS OPEN_VERSIONS USERS_OPENING FETCHES EXECUTIONS USERS_EXECUTING LOADS FIRST_LOAD_TIME INVALIDATIONS PARSE_CALLS DISK_READS BUFFER_GETS ROWS_PROCESSED COMMAND_TYPE OPTIMIZER_MODE PARSING_USER_ID PARSING_SCHEMA_ID KEPT_VERSIONS ADDRESS HASH_VALUE MODULE MODULE_HASH ACTION ACTION_HASH SERIALIZABLE_ABORTS CPU_TIME ELAPSED_TIME IS_OBSOLETE CHILD_LATCH

5055374 57624 627480 23 574 21 0 0 43 23 0 583 2005-09-23/13:14:32 0 23 252790 350841 179 3 MULTIPLE CHILDREN PRESENT 0 0 0 00000003CDE56F38 4230421071 pbifs32.exe 0 0 0 30980000 33912380 N 10

You can see the version_count = 574. But, the following were taken from v$sql_shared_cursor for the same address and hash_value:

ADDRESS KGLHDPAR UNBOUND_CURSOR SQL_TYPE_MISMATCH OPTIMIZER_MISMATCH OUTLINE_MISMATCH STATS_ROW_MISMATCH LITERAL_MISMATCH SEC_DEPTH_MISMATCH EXPLAIN_PLAN_CURSOR BUFFERED_DML_MISMATCH PDML_ENV_MISMATCH INST_DRTLD_MISMATCH SLAVE_QC_MISMATCH TYPECHECK_MISMATCH AUTH_CHECK_MISMATCH BIND_MISMATCH DESCRIBE_MISMATCH LANGUAGE_MISMATCH TRANSLATION_MISMATCH ROW_LEVEL_SEC_MISMATCH INSUFF_PRIVS INSUFF_PRIVS_REM REMOTE_TRANS_MISMATCH LOGMINER_SESSION_MISMATCH INCOMP_LTRL_MISMATCH OVERLAP_TIME_MISMATCH SQL_REDIRECT_MISMATCH MV_QUERY_GEN_MISMATCH USER_BIND_PEEK_MISMATCH TYPCHK_DEP_MISMATCH NO_TRIGGER_MISMATCH FLASHBACK_CURSOR
00000003DF71CB50 00000003CDE56F38 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
00000003BF297BA0 00000003CDE56F38 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
.........
.........

There are only 64 rows (child cursors) and no any "Y" value found out.

The cursor_sharing = SIMILAR. Because this is a third party software and we have no control on using bind variables, we set the cursor sharing to "similar". We met the 4031 error before with "exact" (and "force" caused some other errors). We also use auto PGA management instance wide and all user sessions are configured same. The current version for Oracle is 9206 on solaris. So, is there anything that we should check to see why those child cursors were not shared?

Thank you very much!

Tom Kyte
September 24, 2005 - 7:59 am UTC

cursor_sharing=similar is supposed to do this.  You must have an "unsafe" bind in there.  This is the cause.

I'll take the example from:
http://asktom.oracle.com/pls/asktom/f?p=100:11:::::P11_QUESTION_ID:47467066281452#47763551577367

and stop it short - showing the multiple cursors, without any Y's:

ops$tkyte@ORA9IR2> drop table t;
 
Table dropped.
 
ops$tkyte@ORA9IR2> alter system flush shared_pool;
 
System altered.
 
ops$tkyte@ORA9IR2> create table t
  2  as
  3  select object_id, rpad('*',20,'*') data
  4    from all_objects
  5   union all
  6  select 0, rpad('*',20,'*') data
  7    from all_objects
  8  /
 
Table created.
 
ops$tkyte@ORA9IR2> create index t_idx on t(object_id);
 
Index created.
 
ops$tkyte@ORA9IR2> exec dbms_stats.gather_table_stats( user, 'T', method_opt => 'for all indexed columns size 254', cascade => true );
 
PL/SQL procedure successfully completed.
 
ops$tkyte@ORA9IR2> set autotrace traceonly explain
ops$tkyte@ORA9IR2> select * from t where object_id = 55;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=2 Card=1 Bytes=16)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'T' (Cost=2 Card=1 Bytes=16)
   2    1     INDEX (RANGE SCAN) OF 'T_IDX' (NON-UNIQUE) (Cost=1 Card=1)
 
 
 
ops$tkyte@ORA9IR2> select * from t where object_id = 0;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=38 Card=27603 Bytes=441648)
   1    0   TABLE ACCESS (FULL) OF 'T' (Cost=38 Card=27603 Bytes=441648)
 
 
 
ops$tkyte@ORA9IR2> set autotrace off
ops$tkyte@ORA9IR2> alter session set cursor_sharing=similar;
 
Session altered.
 
ops$tkyte@ORA9IR2> set autotrace traceonly statistics;
ops$tkyte@ORA9IR2> select * from t where object_id= 55;
 
 
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
          4  consistent gets
          0  physical reads
          0  redo size
        453  bytes sent via SQL*Net to client
        499  bytes received via SQL*Net from client
          2  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
          1  rows processed
 
ops$tkyte@ORA9IR2> select * from t where object_id= 0;
 
27822 rows selected.
 
 
Statistics
----------------------------------------------------------
          0  recursive calls
          0  db block gets
       2085  consistent gets
          0  physical reads
          0  redo size
     363945  bytes sent via SQL*Net to client
      20893  bytes received via SQL*Net from client
       1856  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      27822  rows processed
 
ops$tkyte@ORA9IR2> set autotrace off
ops$tkyte@ORA9IR2> column sql_text format a30
ops$tkyte@ORA9IR2> column address new_val ADDR
ops$tkyte@ORA9IR2> select parsing_user_id puid, parsing_schema_id psid,
  2         sql_text, address, child_address
  3    from v$sql
  4   where sql_text like 'select * from t where object_id= %';
 
      PUID       PSID SQL_TEXT                       ADDRESS  CHILD_AD
---------- ---------- ------------------------------ -------- --------
       372        372 select * from t where object_i 60D959D0 60D945B4
                      d= :"SYS_B_0"
 
       372        372 select * from t where object_i 60D959D0 60D76C00
                      d= :"SYS_B_0"
 
 
ops$tkyte@ORA9IR2> select *
  2    from v$sql_shared_cursor
  3   where KGLHDPAR = '&ADDR'
  4  /
old   3:  where KGLHDPAR = '&ADDR'
new   3:  where KGLHDPAR = '60D959D0'
 
ADDRESS  KGLHDPAR U S O O S L S E B P I S T A B D L T R I I R L I O S M U T N F
-------- -------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
60D945B4 60D959D0 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
60D76C00 60D959D0 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N
 
ops$tkyte@ORA9IR2>



<b>this is what cursor_sharing=similar is designed to do -- gives you the POSSIBILITY of reducing the number of child cursors.  But if a bind is detected as "not safe", it will become part of the signature of that child cursor and only sql with the same binds can reuse it.

Your 3rd party product has a serious bug, I'd be bashing on that vendor hard - really hard - to have it fixed.
</b>
(I still wonder why we have technlogy "bake offs", benchmark databases, drill down on how they work when we purchase them, but when it comes to an application, those with the prettiest screens win :(  We don't see to evaluate them using the same standards we do with core technology like an app server or database.  But we should)


Do you gather histograms with size greater than one?  That is what made the bind "unsafe" in this example... 

We'll work on the issue and post back if found the bugs

Julie, September 25, 2005 - 10:31 am UTC

Thank you very much, Tom!

Just like you said, we're using size "auto" for all indexed columns. We did not specify the "method_opt" before so that's why we did not hit the bug. We just recently changed our stats collection to use "auto" for all indexed columns.

-Julie

ROWS_PROCESSED column in V$SQLAREA

Suvendu, October 13, 2005 - 1:59 pm UTC

Hi Tom,

Someone told me, when a long running UPDATE or DELETE statement going on executing, refering to v$sqlarea views ROWS_PROCESSED column we can find out sofar how much rows processed. But the document says, it will update after the statement is complete.

"ROWS_PROCESSED
= The total number of rows processed on behalf of this SQL statement"

But, here my requirment is same to know, please could you elaborate same with a test case.

Correct me if I'm wrong.

Thanking you,

Regards,
Suvendu

Tom Kyte
October 13, 2005 - 6:34 pm UTC

rows processed is updated at the end of the call.

just try "delete from t" where t is big and query and you'll see.

How to know, how many rows processed and how many remaining there?

Suvendu, October 14, 2005 - 4:50 am UTC

Hi Tom,

Thanks a lot for your input.

I'm agree with you. The scenario is like that, the user issued the co-related DELETE statement on a 100 million FACT table, and it already ran for last five hours and it is continuing. And I knows it have to delete 2 million records, and now I have to check out how many rows so far processed and how many rows need to processed and how long I need to wait for this query to complete else I'll kill the session.

And I knows it's not a feasible way to do, where we can go for the options like CTAS rather than such type of DELETE statement.

Please, could you share your view on my understanding? And correct me if I'm wrong.

Thanking you.

Regards,
Suvendu


Tom Kyte
October 14, 2005 - 8:05 am UTC

depending on the query plan - look in v$session_longops where time_remaining > 0.

see if you see your session in there, if so, it'll have an estimate.


if the query plan includes nested loops operations however, it may well not have an entry in v$session_longops.



To delete 2% of the rows from a table - I would probably use a delete.

Thanks

Reader, March 12, 2007 - 1:01 pm UTC

Why is the query parsed everytime even though Iam using the variable? On 2nd Run it should not have parsed. Similarly on 3rd and 4th Run.


SQL> select optimizer_mode, parse_calls, executions, VERSION_COUNT, sql_text
2 from v$sqlarea where sql_text like
3 'select c1 from t1%'
4 /

no rows selected

SQL> alter session set cursor_sharing=similar;

Session altered.

1st Run
-------

SQL> select c1 from t1 where rownum < &1
2 ;
Enter value for 1: 2
old 1: select c1 from t1 where rownum < &1
new 1: select c1 from t1 where rownum < 2

C1
---------------
000000000000003

SQL> select optimizer_mode, parse_calls, executions, VERSION_COUNT, sql_text
2 from v$sqlarea where sql_text like
3 'select c1 from t1%'
4 /

OPTIMIZER_MODE PARSE_CALLS EXECUTIONS VERSION_COUNT
------------------------- ----------- ---------- -------------
SQL_TEXT
--------------------------------------------------------------------------------
CHOOSE 1 1 1
select c1 from t1 where rownum < :"SYS_B_0"


2nd Run
-------

SQL> select c1 from t1 where rownum < &1;
Enter value for 1: 2
old 1: select c1 from t1 where rownum < &1
new 1: select c1 from t1 where rownum < 2

C1
---------------
000000000000003

SQL> select optimizer_mode, parse_calls, executions, VERSION_COUNT, sql_text
2 from v$sqlarea where sql_text like
3 'select c1 from t1%'
4 /

OPTIMIZER_MODE PARSE_CALLS EXECUTIONS VERSION_COUNT
------------------------- ----------- ---------- -------------
SQL_TEXT
--------------------------------------------------------------------------------
CHOOSE 1 1 1
select c1 from t1 where rownum < :"SYS_B_0"

CHOOSE 1 1 1
select c1 from t1 where rownum < :"SYS_B_0"

3rd Run
-------
SQL> select c1 from t1 where rownum < 2;

C1
---------------
000000000000003

SQL> select optimizer_mode, parse_calls, executions, VERSION_COUNT, sql_text
2 from v$sqlarea where sql_text like
3 'select c1 from t1%'
4 /

OPTIMIZER_MODE PARSE_CALLS EXECUTIONS VERSION_COUNT
------------------------- ----------- ---------- -------------
SQL_TEXT
--------------------------------------------------------------------------------
CHOOSE 2 2 1
select c1 from t1 where rownum < :"SYS_B_0"

CHOOSE 1 1 1
select c1 from t1 where rownum < :"SYS_B_0"


4th Run
-------

SQL> select c1 from t1 where rownum < &1;
Enter value for 1: 2
old 1: select c1 from t1 where rownum < &1
new 1: select c1 from t1 where rownum < 2

C1
---------------
000000000000003

SQL> select optimizer_mode, parse_calls, executions, VERSION_COUNT, sql_text
2 from v$sqlarea where sql_text like
3 'select c1 from t1%'
4 /

OPTIMIZER_MODE PARSE_CALLS EXECUTIONS VERSION_COUNT
------------------------- ----------- ---------- -------------
SQL_TEXT
--------------------------------------------------------------------------------
CHOOSE 3 3 1
select c1 from t1 where rownum < :"SYS_B_0"

CHOOSE 1 1 1
select c1 from t1 where rownum < :"SYS_B_0"


Tom Kyte
March 12, 2007 - 8:33 pm UTC

because you are using a command line tool that has logic that looks like:

loop
   read input from user
   if input says "please exit" then EXIT the loop and quit
   else
      parse input
      bind input
      execute input
      close input
   end if
end loop


we parse everytime you ask us to parse. cursor sharing WILL NEVER EVER REDUCE THE NUMBER OF PARSE CALLS

there is precisely one person on the planet that can reduce parse calls - that is the person that wrote the application - period.

cursor sharing can be used to turn

a) a hard parse which is very very very bad into
b) a soft parse which is only very very bad and session_cached_cursors can turn that into
c) what I call a softer soft parse which is only very bad

however, only a programmer can produce the only good parse in Oracle which is

d) the absence of a parse, no parse

Thanks

Reader, March 14, 2007 - 6:57 am UTC

Thanks for the previous reply.
We have a Remedy application accessing Oracle 9i DB. I was looking at the STATSPACK Top SQL Queries. I was wondering why almost each and every query is been parsed. Then I looked at the log file which are created by Remedy Server before sending the queries to Oracle DB.

This is an extract from log file.

SELECT actlinkId,name FROM actlink WHERE actlinkId=30447 ORDER BY 1 DESC
SELECT actlinkId,name FROM actlink WHERE actlinkId=30448 ORDER BY 1 DESC
SELECT actlinkId,name FROM actlink WHERE actlinkId=30449 ORDER BY 1 DESC
SELECT actlinkId,name FROM actlink WHERE actlinkId=30450 ORDER BY 1 DESC

Is this not ridiculas now that we cannot do anything but live with this?

Is there any way parameter setting I can do in Oracle where the parsing can be reduced )


Tom Kyte
March 14, 2007 - 8:04 am UTC

parsing reduced? No, never, only a program can reduce the number of parse calls.

change the type of parsing from hard to soft? yes, cursor_sharing=force|similar can do that - however, you need to get the makers of remedy to say "yes, that'll be ok to set, no problem, we'll support you still"

Thanks

Reader, March 14, 2007 - 9:50 am UTC

Thanks for the reply. Even though CURSOR_SHARING is set to SIMILAR, Iam seeing most of the statements are parsed.

Here is my simple analysis.

SQL> select count(1) from v$sqlarea where parse_calls = executions;

COUNT(1)
----------
55671

SQL> select count(1) from v$sqlarea

COUNT(1)
----------
55792

Which is roughly 99%.
Tom Kyte
March 14, 2007 - 2:01 pm UTC

i'll say it again.... (and again and again)


parsing reduced? No, never, only a program can reduce the number of parse calls.


cursor sharing CANNOT, WILL NOT reduce the number of parse calls

the very best it can do is turn a hard into a soft parse.

ONLY the programmer can reduce parse calls, nothing but nothing else can..

Oracle will "parse" when asked to "parse", they asked us to parse, we cannot stop them from asking us to do that

More to Explore

Performance

Get all the information about database performance in the Database Performance guide.