This article mainly covers importance of SESSION_CACHED_CURSORS on performance and open cursors . Apart from SESSION_CACHED_CURSORS , other parameters that control open cursors in database are cursor_sharing and how developers close cursor in pl/sql block .
specifies the maximum number of open cursors (handles to private SQL areas) a
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 re-executed by a user.
SESSION_CACHED_CURSORS
lets you specify the number of session cursors to cache. Repeated
parse calls of the same SQL statement cause the session cursor for that statement to be moved into the
session cursor cache. Subsequent parse calls will find the cursor in the cache and do not need to reopen
the cursor.
If the session cursor cache count is maxed out, session_cursor_cache_hits is low compared to all parses, and you suspect that the application is re-submitting the same queries for parsing repeatedly, then increasing SESSION_CURSOR_CACHE_COUNT may help with latch contention and give a slight boost to performance. Note that if your application is not resubmitting the same queries for parsing repeatedly, then session_cursor_cache_hits will be low and the session cursor cache count may be maxed out, but caching cursors by session will not help at all. For example, if your application is using a lot of unsharable SQL, raising this parameter will not help
When a SQL statement is issued, the server process, after checking its syntax and semantics, searches the library cache for an existing cursor for the SQL statement. If a cursor does not already exist, a new cursor is created (hard parse), else existing cursor is used (soft parse). Whereas hard parsing is a resource intensive operation, soft parse, although less expensive, also incurs some cost, as the server process has to search the library cache for previously parsed SQL, which requires the use of the library cache and shared pool latches. Latches can often become points of contention for busy OLTP systems, thereby affecting response time and scalability.
To minimize the impact on performance, session cursors of repeatedly issued statements can be stored in the session cursor cache to reduce the cost of or even eliminate soft parse. This is called Session Cursor Caching. When session cursor caching is enabled, Oracle caches the cursor of a reentrant SQL statement in the session memory (PGA / UGA). As a result, the session cursor cache now contains a pointer into the library cache where the cursor existed when it was closed. Since presence of a cursor in session cursor cache guarantees the correctness of the corresponding SQL’s syntax and semantics, these checks are bypassed when the same SQL is resubmitted. Subsequently, instead of searching for the cursor in library cache, the server process follows the pointer in the session memory and uses the cursor after having confirmed its presence and validity.
Hence, if a closed cursor is found in the session cursor cache, it is registered as a ‘session cached cursor hit’ and also as a ‘soft parse’, since a visit to the shared SQL area must be made to confirm its presence and validity
Handling Cursor from Pl/SQL side Using Precompiler Option RELEASE_CURSOR=YES
Well this is totally different topic altogether hence not sharing too much information on this. However just to give direction to developer on cursor handling can be done at coding side ,
select sid , count(*) from v$open_cursor group by sid order by 2 ;
C.ADDRESS || ':' || C.HASH_VALUE AS "SQL Address",
COUNT(C.SADDR) AS "Cursor Copies"
FROM V$OPEN_CURSOR C
GROUP BY C.SID, C.ADDRESS || ':' || C.HASH_VALUE
HAVING COUNT(C.SADDR) > 2
ORDER BY 3 DESC
/
'session_cached_cursors' parameter,
LPAD(value, 5) value,
DECODE(value, 0, ' n/a', to_char(100 * used / value, '990') ||
'%') usage
FROM
(SELECT
MAX(s.value) used
FROM
v$statname n,
v$sesstat s
WHERE
n.name = 'session cursor cache count' and
s.statistic# = n.statistic#
),
(SELECT
value
FROM
v$parameter
WHERE
name = 'session_cached_cursors'
)
UNION ALL
SELECT
'open_cursors',
LPAD(value, 5),
to_char(100 * used / value, '990') || '%'
FROM
(SELECT
MAX(sum(s.value)) used
FROM
v$statname n,
v$sesstat s
WHERE
n.name in ('opened cursors current', 'session cursor cache
count') and
s.statistic# = n.statistic#
GROUP BY
s.sid
),
(SELECT
value
FROM
v$parameter
WHERE
name = 'open_cursors'
)
/
SELECT b.SID, UPPER(a.NAME), b.VALUE
FROM v$statname a, v$sesstat b, v$session c
WHERE a.statistic# = b.statistic#
AND c.SID = b.SID
AND LOWER(a.NAME) LIKE '%' || LOWER('CURSOR')||'%'
AND b.SID=20
UNION
SELECT SID, 'v$open_cursor opened cursor', COUNT(*)
FROM v$open_cursor
WHERE SID=&sid
GROUP BY SID
ORDER BY SID
/
s.username, s.sid, s.serial#
FROM v$sesstat a, v$statname b, v$session s, v$parameter2 p
WHERE a.statistic# = b.statistic# and s.sid=a.sid and a.sid=&sid
AND p.name='session_cached_cursors'
AND b.name = 'session cursor cache count';
select s.username, s.sid, s.serial#, 'CACHED_CURSORS'
Statistic,
a.value
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and s.username='HAFEEZ'
and b.name in ('session cursor cache count')
union
select s.username, s.sid, s.serial#, 'CURSORS_HITS',
a.value
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and s.username='HAFEEZ'
and b.name in ( 'session cursor cache hits')
union
select s.username, s.sid, s.serial#, 'PARSES',
a.value
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and s.username='HAFEEZ'
and b.name in ( 'parse count (total)')
union
select s.username, s.sid, s.serial#, 'HARD PARSES',
a.value
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and s.username='HAFEEZ'
and b.name in ( 'parse count (hard)') ;
-- CHECKING DETAIL OF PARTICULAR SQL ID
SELECT
CHILD_NUMBER CN,
NAME,
VALUE,
ISDEFAULT DEF
FROM
V$SQL_OPTIMIZER_ENV
WHERE
SQL_ID='5ngzsfstg8tmy'
AND CHILD_NUMBER in (0,2,12)
ORDER BY
NAME,
CHILD_NUMBER;
SELECT
CHILD_NUMBER CN,
PARSING_SCHEMA_NAME,
OPTIMIZER_ENV_HASH_VALUE OPTIMIZER_ENV,
INVALIDATIONS,
PARSE_CALLS,
IS_OBSOLETE,
FIRST_LOAD_TIME,
TO_CHAR(LAST_ACTIVE_TIME,'YYYY-MM-DD/HH24:MI:SS') LAST_ACTIVE_TIME
FROM
V$SQL
WHERE
SQL_ID='5ngzsfstg8tmy';
It is important to be able to diagnose which cursor is being 'leaked' (not closed) to identify what part of the application is responsible for managing the cursor,
Lists each cursor, which has been opened by the session more than once in descending order.
SELECT COUNT(*), address
2 FROM v$open_cursor
3 WHERE sid = 135
4 GROUP BY address HAVING COUNT(address) > 1 ORDER BY COUNT(*);
ALTER SYSTEM SET EVENTS '1000 trace name errorstack level 3';
Bugs Related to Cursors :
1) BUG 30518349 - ORA-01000 SELECT DOCID FROM "DR#IX_TS0481$U" , "DR#IX_TS0481$K"...
2) Bug 23608322 - CURSOR LEAK WITH DBMS_SQL.RETURN_RESULT IN JDBC THIN DRIVER 12.1.0.2 was opened for this issue.
References :
https://docs.oracle.com/cd/B10501_01/appdev.920/a97269/pc_10opt.htm
No comments:
Post a Comment