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.
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!
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
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
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"
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 )
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%.
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