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

Home -> Community -> Mailing Lists -> Oracle-L -> RE: OPEN_CURSORS !

RE: OPEN_CURSORS !

From: Juan Carlos Reyes Pacheco <jreyes_at_dazasoftware.com>
Date: Wed, 14 Jul 2004 17:14:39 -0400
Message-Id: <40F5A23F.000009.01052@CACHITOSS>


Hi based on my few understanding a cursor is a query, not what you get from it.  

I hope not to bore you but here is something I investigate about this parameter sometime ago and will be in my next paper, I need to check once again.

Anything wrong someone could find tellme please

1 open_cursors parameter

6.1 What it’s for? 
6.1.1 Precompilers Programs 
6.1.2 Heterogeneous Services 
6.1.3 Relation with session_cached_cursors 
6.2 Syntax 
6.3 Evaluating the accuracy of the value 
6.3.1 V$OPEN_CURSOR 
6.3.2 Stat: opened cursors current 
6.4 Examples 
6.4.1 Closing Cursors 
1.1 What it’s for?

Specifies the maximum number of open cursors (handles to private SQL areas) each session can have at once. You can use this parameter to prevent a session from opening an excessive number of cursors. This parameter also constrains the size of the PL/SQL cursor cache which PL/SQL uses to avoid having to reparse as statements are reexecuted by a user. If the limit is exceeded an ORA-01000 error is fired, and you should have to increase this parameter’s value.
This parameter can too be used in trigger cascading, when a statement in a trigger body causes another trigger to be fired, the triggers are said to be cascading. Oracle allows up to 32 triggers to cascade at any one time. However, you can effectively limit the number of trigger cascades using the initialization parameter OPEN_CURSORS, because a cursor must be opened for every execution of a trigger.
If your program exceeds the limit imposed by OPEN_CURSORS, Oracle gives you an error.
Assuming that a session does not open the number of cursors specified by OPEN_CURSORS, there is no added overhead to setting this value higher than actually needed.
Cursors are allocated 64 at a time up to OPEN_CURSORS so having it set high is OK. The recommended value is between 0 and 10,000 open cursor will allocate an array in the session space (smallish). 200 would be fine for most. Reports, Forms, etc they all use a large number of cached cursors. 500-1000 (recommend 1000).
It should be noted that OPEN_CURSORS simply allocates a fixed number of slots but does not allocate memory for these slots for a client (eg: it sets an array up to have 1,000 cursors for example but does not allocate 1,000 cursors).
The management of private SQL areas is the responsibility of the user process. The allocation and deallocation of private SQL areas depends largely on which application tool you are using, although the number of private SQL areas that a user process can allocate is always limited by the initialization parameter It is important to set the value of OPEN_CURSORS high enough to prevent your application from running out of open cursors. The number will vary from one application to another. Applications should close unneeded cursors to conserve system memory. If a cursor cannot be opened due to a limit on the number of cursors  

To take advantage of the additional memory available for shared SQL areas, you may also need to increase the number of cursors permitted per session. You can increase this limit by increasing the value of the initialization parameter OPEN_CURSORS.
Be careful where you place a recursive call. If you place it inside a cursor FOR loop or between OPEN and CLOSE statements, another cursor is opened at each call. As a result, your program might exceed the limit set by the Oracle initialization parameter OPEN_CURSORS. 1.1.1 Precompilers Programs
When writing precompiler programs, increasing the number of cursors using MAX_OPEN_CURSORS can often reduce the frequency of parsing and improve performance.
Oracle allocates an additional cache entry if it cannot find one to reuse. For example, if MAXOPENCURSORS=8 and all eight entries are active, a ninth is created. If necessary, Oracle keeps allocating additional cache entries until it runs out of memory or reaches the limit set by OPEN_CURSORS. This dynamic allocation adds to processing overhead. MAXOPENCURSORS specifies the initial size of the cursor cache. If a new cursor is needed and there are no free cache entries, the server tries to reuse an entry. Its success depends on the values of HOLD_CURSOR and RELEASE_CURSOR and, for explicit cursors, on the status of the cursor itself

If the value of MAXOPENCURSORS is less than the number of cache entries actually needed, the server uses the first cache entry marked as reusable. For example, suppose an INSERT statement's cache entry E(1) is marked as reusable, and the number of cache entries already equals MAXOPENCURSORS. If the program executes a new statement, cache entry E(1) and its private SQL area might be reassigned to the new statement. To reexecute the INSERT statement, the server would have to reparse it and reassign another cache entry.
Thus, specifying a low value for MAXOPENCURSORS saves memory but causes potentially expensive dynamic allocations and deallocations of new cache entries. Specifying a high value for MAXOPENCURSORS assures speedy execution but uses more memory.
A system-wide limit of cursors for each session is set by the initialization parameter named OPEN_CURSORS found in the parameter file (such as INIT.ORA). 1.1.2 Heterogeneous Services
HS_OPEN_CURSORS FOR Heterogeneous Services, defines the maximum number of cursors that can be open on one connection to a non-Oracle system instance. 1.1.3 Relation with session_cached_cursors None relation.
session_cached_cursors -- how many cached CLOSED cursors you can have. open_cursor -- how many concurrently opened cursors you can have. ops$tkyte_at_ORA920> show parameter _cursors NAME TYPE VALUE

------------------------------------ -----------
------------------------------

open_cursors integer 50
session_cached_cursors integer 100
that means, "you cannot have more then 50 open at the same time - but we might cache 100 of them for you off to the side..." ops$tkyte_at_ORA920> @mystat cursor
ops$tkyte_at_ORA920> select a.name, b.value 2 from v$statname a, v$mystat b
3 where a.statistic# = b.statistic#
4 and lower(a.name) like '%' || lower('&1')||'%' 5 /
old 4: and lower(a.name) like '%' || lower('&1')||'%' new 4: and lower(a.name) like '%' || lower('cursor')||'%' NAME VALUE
------------------------------ ----------
opened cursors cumulative 26
opened cursors current 9
session cursor cache hits 0
session cursor cache count 13
cursor authentications 1  

ops$tkyte_at_ORA920> declare
2 type rc is ref cursor;
3
4 l_cursor rc;
5 begin
6 for i in 1 .. 100
7 loop
8 for j in 1 .. 5
9 loop
10 open l_cursor for 'select * from dual xx' || i; 11 close l_cursor;
12 end loop;
13 end loop;
14 end;
15 /
PL/SQL procedure successfully completed.  

ops$tkyte_at_ORA920>
ops$tkyte_at_ORA920> @mystat cursor
ops$tkyte_at_ORA920> select a.name, b.value
2 from v$statname a, v$mystat b
3 where a.statistic# = b.statistic#
4 and lower(a.name) like '%' || lower('&1')||'%' 5 /
old 4: and lower(a.name) like '%' || lower('&1')||'%' new 4: and lower(a.name) like '%' || lower('cursor')||'%' NAME VALUE
------------------------------ ----------
opened cursors cumulative 529
opened cursors current 9
session cursor cache hits 400
session cursor cache count 100
cursor authentications 1
that shows I've 100 cursors in my "cache" ready to be opened faster then normal -- but I never exceeded my 50 open cursors at a time threshold. 1.2 Syntax
You can set this parameter with
ALTER SESSION SET OPEN_CURSORS = value
ALTER SYSTEM SET OPEN_CURSORS = value [DEFERRED] In parameter file
set OPEN_CURSORS = (number), default value 50 1.3 Evaluating the accuracy of the value While executing an embedded PL/SQL block, one cursor. the parent cursor, is associated with the entire block and one cursor, the child cursor, is associated with each SQL statement in the embedded PL/SQL block. Both parent and child cursors count toward the OPEN_CURSORS limit. The following calculation shows how to determine the maximum number of cursors used. The sum of the cursors used must not exceed OPEN_CURSORS. SQL statement cursors
PL/SQL parent cursors
PL/SQL child cursors
+ 6 cursors for overhead

Sum of cursors in use
The Oracle9i default of 50 or so is too small to accommodate Oracle Internet Directory server cursor cache. Note that this value is not dependent on other Oracle Internet Directory server parameters, such as # SERVERS and # WORKERS. The value of 200 is sufficient for any size DIT. 1.3.1 V$OPEN_CURSOR
V$OPEN_CURSOR represents a set of cached cursors the server has for you. 1.3.2 Stat: opened cursors current
Is Total number of current open cursors
This statistics gives you the actual number of truely open cursors --For current session
select a.value, b.name
from v$mystat a, v$statname b
where a.statistic# = b.statistic#
and b.name = 'opened cursors current', for current session --For all sessions
select a.sid, a.value, b.name
from v$sesstat a, v$statname b
where a.statistic# = b.statistic#
and b.name = 'opened cursors current'
order by value desc
1.4 Examples
1.4.1 Closing Cursors
1.4.1.1 Closing ref cursor explicitly

How, would I close a ref cursor, after I fetch from it. It depends on the language.
Pro*c: EXEC SQL CLOSE :ref_cursor_variable; SQLPlus: mplicit
PLSQL: Close ref_cursor_variable;
Java: rset.close();
and so on.
1.4.1.2 Closing cursor in PLSQL
ops$tkyte_at_ORA817DEV.US.ORACLE.COM> create or replace package types 2 as
3 type rc is ref cursor;
4 end;
5 /
Package created.  

ops$tkyte_at_ORA817DEV.US.ORACLE.COM>
ops$tkyte_at_ORA817DEV.US.ORACLE.COM> create or replace function foo return types.rc
2 as
3 l_cursor types.rc;
4 begin
5 open l_cursor for select * from dual;
6 return l_cursor;
7 end;
8 /
Function created.  

ops$tkyte_at_ORA817DEV.US.ORACLE.COM>
ops$tkyte_at_ORA817DEV.US.ORACLE.COM> create or replace procedure bar 2 as
3 l_cursor types.rc;
4 l_rec dual%rowtype;
5 begin
6 l_cursor := foo;
7 loop
8 fetch l_cursor into l_rec;
9 exit when l_cursor%notfound;
10 dbms_output.put_line( l_rec.dummy );
11 end loop;
12 close l_cursor;
13 end;
14 /
Procedure created.  

ops$tkyte_at_ORA817DEV.US.ORACLE.COM>
ops$tkyte_at_ORA817DEV.US.ORACLE.COM> exec bar X  

PL/SQL procedure successfully completed. 1.4.1.3 Closing cursor in Java
Cursors will remain there until you run out of slots in your OPEN CURSOR array --
at which point they are flushed if not currently being used (plsql lets them
"go

away" if and when the server needs that slot) They do not count against you, they are there for performance. It is an EXCELLENT reason why most java programs entire suite of SQL should consist of
nothing more then begin .... end; -- never any actual DML of its own. More manageable, more flexible.
You can test this out yourself by using this: create or replace package demo_pkg
as
type refcur is ref cursor;  

procedure get_cur( x in out refcur );
end;
/
create or replace package body demo_pkg
as
g_first_time boolean default true;
procedure get_cur( x in out refcur )
is
l_user varchar2(1000);
begin
open x for select USER from dual THIS_IS_A_JAVA_CURSOR; if ( g_first_time )
then
select user
into l_user
from dual THIS_IS_PLSQL where rownum = 1; select user
into l_user
from dual THIS_TOO_IS_PLSQL where rownum = 1; g_first_time := false;
end if;
end;
end;
/  

that plsql only needs the cursors for a bit -- we don't need them everytime. .  

Now I modified the java to be:  

public static void main (String args []) throws SQLException, ClassNotFoundException {
String query =
"begin demo_pkg.get_cur( :1 ); end;";
 

DriverManager.registerDriver
(new oracle.jdbc.driver.OracleDriver());  

Connection conn=
DriverManager.getConnection
("jdbc:oracle:oci8:@ora817dev",
"scott", "tiger");
 

showOpenCnt( conn, "Before Anything" );  

CallableStatement cstmt = conn.prepareCall(query); cstmt.registerOutParameter(1,OracleTypes.CURSOR);  

for( int j = 0; j < 100; j++ )
{
cstmt.execute();
showOpenCnt( conn, j + ") After prepare and execute" );  

ResultSet rset = (ResultSet)cstmt.getObject(1);  

for(int i = 0; rset.next(); i++ );
}  

cstmt.close();
showOpenCnt( conn, "After CallableStatement closes" ); }  

I don't close the result sets - we just let them leak all over the place. I have open_cursors set to 50 and run:  

> !java
java curvar



Before Anything

1 opened cursors current

Open Cursors Currently
SID***8 SELECT VALUE FROM NLS_INSTANCE_PARAMETERS WHERE PARAMETER ='
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 ALTER SESSION SET NLS_TERRITORY = 'AMERICA'
SID***8 ALTER SESSION SET NLS_LANGUAGE = 'AMERICAN'
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
-----------------------
====================================

0) After prepare and execute

5 opened cursors current

Open Cursors Currently
SID***8 SELECT VALUE FROM NLS_INSTANCE_PARAMETERS WHERE PARAMETER ='
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 SELECT USER FROM DUAL THIS_IS_PLSQL WHERE ROWNUM = 1
SID***8 begin demo_pkg.get_cur( :1 ); end;
SID***8 ALTER SESSION SET NLS_TERRITORY = 'AMERICA'
SID***8 ALTER SESSION SET NLS_LANGUAGE = 'AMERICAN'
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
SID***8 SELECT USER FROM DUAL THIS_TOO_IS_PLSQL WHERE ROWNUM = 1
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
-----------------------
====================================

1) After prepare and execute
 

6 opened cursors current



Open Cursors Currently
SID***8 SELECT VALUE FROM NLS_INSTANCE_PARAMETERS WHERE PARAMETER ='
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 SELECT USER FROM DUAL THIS_IS_PLSQL WHERE ROWNUM = 1
SID***8 begin demo_pkg.get_cur( :1 ); end;
SID***8 ALTER SESSION SET NLS_TERRITORY = 'AMERICA'
SID***8 ALTER SESSION SET NLS_LANGUAGE = 'AMERICAN'
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
SID***8 SELECT USER FROM DUAL THIS_TOO_IS_PLSQL WHERE ROWNUM = 1
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
-----------------------
 

note that after each iteration I got more and more "this is a java cursor". The plsql guys stayed in there.... UNTIL:  



45) After prepare and execute

50 opened cursors current

Open Cursors Currently
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 SELECT USER FROM DUAL THIS_IS_PLSQL WHERE ROWNUM = 1
SID***8 begin demo_pkg.get_cur( :1 ); end;
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
SID***8 SELECT USER FROM DUAL THIS_TOO_IS_PLSQL WHERE ROWNUM = 1
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
<lots of those chopped out>
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR


46) After prepare and execute

49 opened cursors current

Open Cursors Currently
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 begin demo_pkg.get_cur( :1 ); end;
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
<lots chopped NOTE: PLSQL cursors *gone*> SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR


47) After prepare and execute

50 opened cursors current

Open Cursors Currently
SID***8 select a.value, b.name from v$mystat a, v$statname b where a
SID***8 begin demo_pkg.get_cur( :1 ); end;
SID***8 select sid, sql_text from v$open_cursor where sid = (select 
SID***8 ALTER SESSION SET NLS_LANGUAGE= 'AMERICAN' NLS_TERRITORY= 'A
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
..
SID***8 SELECT USER FROM DUAL THIS_IS_A_JAVA_CURSOR
 

java.sql.SQLException: ORA-01000: maximum open cursors exceeded  

at java.lang.Throwable.<init>(Compiled Code)
at java.lang.Exception.<init>(Compiled Code)
at java.sql.SQLException.<init>(Compiled Code)
at oracle.jdbc.dbaccess.DBError.throwSqlException(Compiled Code)
at oracle.jdbc.oci8.OCIDBAccess.check_error(Compiled Code)
at oracle.jdbc.oci8.OCIDBAccess.parseExecuteDescribe(Compiled Code)
at oracle.jdbc.driver.OracleStatement.doExecuteQuery(Compiled Code) at oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(Compiled Code)
at oracle.jdbc.driver.OracleStatement.executeQuery(Compiled Code)
at curvar.showOpenCnt(Compiled Code)
at curvar.main(Compiled Code)
----------------------------------------------------------------
Please see the official ORACLE-L FAQ: http://www.orafaq.com

To unsubscribe send email to: oracle-l-request_at_freelists.org put 'unsubscribe' in the subject line.
--
Archives are at http://www.freelists.org/archives/oracle-l/
FAQ is at http://www.freelists.org/help/fom-serve/cache/1.html
-----------------------------------------------------------------
Received on Wed Jul 14 2004 - 16:16:54 CDT

Original text of this message

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