Skip to Main Content
  • Questions
  • If session_cached_cursors is set,oralce also cache SQL statement in PGA ,if we are using Dedicated server?

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, jiang huang.

Asked: February 27, 2008 - 8:37 am UTC

Last updated: April 12, 2011 - 12:06 pm UTC

Version: 9.2.0

Viewed 1000+ times

You Asked

Hi Tom

Good to have a chance to ask a quesion..

I read some discussions about the session_cached_cursors here in the forum. Would you please help to clarify the idea that:
1.If session_cached_cursors is set to non zero, I understand that oracle caches the cursor in the PGA(dedicated server mode). My qustion is: Is that SQL STATEMENT pointed by cursor also cached in the PGA?

2.If Cursor is cached , will oracle also try to pin the execution plan related to that curor in the Shared pool?

3. If 2 is true,So that could be the reason why we should not oversize the parameter session_cached_cursors to avoid the ora-04031 error?

I am using oracle 9i(9.2.0.1),clients connect in dedicated server mode.

Thank you for taking a look at my question!

and Tom said...

with session cached cursor, you have a "softer soft parse"

In your process memory, pga, when you close a cursor with session cached cursors - instead of just totally losing "everything", we do a normal close from the server perspective but keep a pointer to the shared pool.

when you reparse that sql statement, we follow that pointer (requires latching and such - it is NOT FREE, it is just slightly less expensive than a soft parse, hence I call it a softer soft parse) and see of the statement is still in the shared pool - we can in effect skip a bit of the parse work (not all, just a bit).

The sql can easily go away in the shared pool.


you would not want to oversize this as every time you parse - we do a linear search through this client array to see if there is a pointer for us. The bigger it is, the more time you spend there.

Rating

  (7 ratings)

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

Comments

clear answer!

jiang huang zheng, February 28, 2008 - 10:41 am UTC

Thanks Tom,and much appreciated!

The sql can easily go away in the shared pool--Clear my doubts...
How oracle caculate cursor handler? by hash the sql statement or some other way?

Best Regards..
Tom Kyte
February 28, 2008 - 11:11 pm UTC

conceptually speaking - we have the "pointer to it" in the shared pool. If you re-open that cursor, we dereference the pointer and see if what used to be pointed to is still there.

that is the level to which we need to know - that we keep a pointer to it, and when you re-open it, we look quick in the shared pool to see if it is the same cursor as before.

sql_id's and hashes are involved - as are hundreds of other bits of data.

Thanks!

jiang huang zheng, February 29, 2008 - 9:16 am UTC

Hi Tom

I think I got what I need to know. Very Good answer!

cursor open,what is the meaning?

jiang huang zheng, May 06, 2008 - 3:11 am UTC

Hello Tom
       I understand that if a session keeps cursor open instead of close it, the soft parse could be avoid if next time the same execution happens. 
    I want to know, what is really means , keep cursor open? For instance , in sqlplus,if I execute :
   select *  from scott.emp; 
   after the output given,Is the cursor just closed immediately?
   if I run  pl/sql: 
   SQL> begin
  2  for x in ( select *  from scott.emp)
  3  loop
  4  null;
  5  end loop;
  6  end;
  7  /

PL/SQL procedure successfully completed.

   How does oracle manage the curosr,same as select *  from scott.emp from sqlplus?
   Close the cursor means discarding the cursor handler, right? Would you give a example that keeps cursor open?

   Thanks!
   
  
     

Tom Kyte
May 07, 2008 - 12:43 am UTC

forget sqlplus for a moment, it is just a simple command line tool, a program, a client, something you could have written yourself.

In plsql - oracle caches cursors for us, when you say "close cursor" (either implicitly as you did above with the cursor for loop - by exiting the loop, or explicitly using close C;) plsql says "yeah, sure, you'll be back, i'll just keep this open for now" - it caches them for us transparently.

That example of yours "keeps the cursor open", you need do nothing (that is the beauty of writing your code in plsql, so many optimizations are part of the language.


In a program outside of the database, that is where you can do this - and you would just not "close" the prepared statement handle and just reuse it over and over.

Thanks,and the cached condition in PLSQL is?

jiang huang zheng, May 16, 2008 - 7:31 am UTC

Hello Tom
Thanks and your answer does enlight me..
correct me if I am wrong:
1. oracle caches cursor automatically if you use a stored procedure.
2. Begin
for x in (select * from...)
loop
insert statement
end loop;
end;
3 , is there any other condition besides above two senarios that oracle automatically caches cursor, I think if you issue BELOWING:
begin
insert into emp values(.....);
end;
Oracle wont caches cursor for me,right?

Thanks again..
Tom Kyte
May 19, 2008 - 3:07 pm UTC

1) as best as it can, yes.

3) wrong, it'll cache that - it is rather easy to SEE. consider:



ops$tkyte%ORA10GR2> create table t ( x int, y int );

Table created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> create or replace procedure foo
  2  as
  3  begin
  4          insert into t values ( 1, 2 );
  5          update t set x = 5;
  6          delete from t;
  7          merge into t using (select 1 x, 2 y from dual) d on (t.x = d.x) when matched then update set y = d.y;
  8
  9          execute immediate 'insert into t values ( 100, 200 )';
 10          execute immediate 'update t set x = 500';
 11          execute immediate 'delete from t where 1=1';
 12          execute immediate 'merge into t using (select 10 x, 20 y from dual) d on (t.x = d.x) when matched then update set y = d.y';
 13  end;
 14  /

Procedure created.

ops$tkyte%ORA10GR2>
ops$tkyte%ORA10GR2> @trace
ops$tkyte%ORA10GR2> alter session set events '10046 trace name context forever, level 12';

Session altered.

ops$tkyte%ORA10GR2> exec foo

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> exec foo

PL/SQL procedure successfully completed.

ops$tkyte%ORA10GR2> exec foo

tkprof will show 1 parse, 3 executes - all cached in this case
INSERT INTO T VALUES ( 1, 2 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      3      0.00       0.00          0          1         23           3
********************************************************************************
UPDATE T SET X = 5

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      3      0.00       0.00          0         21          3           3
********************************************************************************
DELETE FROM T

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      3      0.00       0.00          0         21          6           3
********************************************************************************
MERGE INTO T USING (SELECT 1 X, 2 Y FROM DUAL) D ON (T.X = D.X) WHEN MATCHED
  THEN UPDATE SET Y = D.Y

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          2          0           0
Execute      3      0.00       0.00          0         21          0           0
********************************************************************************
insert into t values ( 100, 200 )

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          0          0           0
Execute      3      0.00       0.00          0          1          5           3
********************************************************************************
update t set x = 500

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      3      0.00       0.00          0         21          3           3
********************************************************************************
delete from t where 1=1

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        1      0.00       0.00          0          1          0           0
Execute      3      0.00       0.00          0         21          6           3
********************************************************************************
merge into t using (select 10 x, 20 y from dual) d on (t.x = d.x) when
  matched then update set y = d.y

call     count       cpu    elapsed       disk      query    current        rows
------- ------  -------- ---------- ---------- ---------- ----------  ----------
Parse        3      0.00       0.00          0          2          0           0
Execute      3      0.00       0.00          0         21          0           0

very helpful..

jiang huang zheng, May 20, 2008 - 3:34 am UTC

thanks, very appreciated!

Why the MERGE was parsed 3 times?

Oren, January 21, 2009 - 8:05 am UTC

In the example, all statements were parsed once and executed 3 times, except for the MERGE statement. Why is that?
Tom Kyte
January 21, 2009 - 1:30 pm UTC

interesting, I didn't see that.

looks like an oversight - they are only caching insert/update/delete..

i filed bug 7831098

Shared Pool

A reader, April 04, 2011 - 11:12 am UTC

Hi Tom,

Lets say we have an DSS system that has been running for a while, can we increase the session_cached_cursors to accommodate all the cursors that will be used by my end users. Like for example lets say my end users does some activity on the system and does produce 100 sql statements to database can I increase the shared pool/PGA/session_cached_cursors to cache this 100 cursors so that we will have a better performance?
Thanks for your time and expert advices..

Thanks
Tom Kyte
April 12, 2011 - 12:06 pm UTC

100 is a pretty normal setting for session_cached_cursors.

This parameter does two things

a) it controls the size of the plsql cursor cache. When you have a "close cursor" (be it implicit or explicit) in plsql, plsql doesn't really close the cursor - it keeps it open. The size of the cache that plsql keeps open is controlled by session_cached_cursors.


b) it controls how many cursors in other languages outside of plsql would be cached in a state that makes a 'softer soft parse' possible.


While you could increase it to cache all cursors an application would have open, that wouldn't be good as the number goes up and up and up. You'll need more client memory (that is where the (b) cache is kept) and you might experience shared pool issues (larger shared pool) due to (a) and (b). Also, the larger the client cache, the long it will take to parse as we have to search this cache before parsing anything.


100 (low 100's) is a pretty good setting