How to Monitor and tune Open and Cached Cursors (Doc ID 1430255.1)

OPEN_CURSORS指定会话一次可以拥有的最大打开游标数(私有SQL区域的句柄)。您可以使用此参数来防止会话打开过多的游标。

例如,如果OPEN_CURSORS设置为100,则每个会话最多可以同时打开100个光标。如果单个会话打开了100个(open_cursors值)游标,则在尝试再打开一个游标时会出现ora-1000错误。

OPEN_CURSORS的默认值为50,但Oracle建议您为大多数应用程序将此值设置为至少500。您必须监视游标使用情况以确定适当的值。

影响游标的两个主要初始化参数是:

* SESSION_CACHED_CURSORS
此参数设置每个会话的最大缓存关闭游标数。默认设置为50.您可以使用此参数来防止会话打开过多的游标,从而填充库高速缓存或强制进行过多的硬解析。此参数对ORA-1000错误或会话将打开的游标数没有影响。相反,OPEN_CURSORS对缓存的游标数没有影响。两个参数之间没有关系。您可以将SESSION_CACHED_CURSORS设置为高于OPEN_CURSORS,因为会话游标未在打开状态下缓存。

* OPEN_CURSORS 
此参数指定会话可以同时打开的最大游标数。

MONITORING OPEN CURSORS
v $ open_cursor按会话显示缓存的游标,而不是当前打开的游标。如果您想知道会话打开了多少游标,请不要查看v $ open_cursor。它显示每个会话的会话游标缓存中的游标,而不是实际打开的游标。

要监视打开的游标,请查询v $ sesstat,其中name ='opens cursors current'。这将按会话给出当前打开的游标数:

-- Total cursors open, by session

select a.value, s.username, s.sid, s.serial#
from   v$sesstat a, v$statname b, v$session s
where  a.statistic# = b.statistic# and s.sid=a.sid
and    b.name = 'opened cursors current';


如果您运行多个具有多个Web服务器的N层应用程序,您可能会发现通过用户名和计算机监视打开的游标很有用:

-- Total cursors open, by username & machine

select sum(a.value) total_cur, avg(a.value) avg_cur, max(a.value) max_cur, s.username, s.machine
from   v$sesstat a, v$statname b, v$session s 
where  a.statistic# = b.statistic# and s.sid=a.sid
and    b.name = 'opened cursors current' 
group by s.username, s.machine
order by 1 desc;

调整OPEN_CURSORS

如果您的会话正在接近您为OPEN_CURSORS设置的限制,请提高它。调整此参数的目的是将其设置得足够高,以便在正常操作期间永远不会获得ORA-1000。

如果将OPEN_CURSORS设置为较高值,则这并不意味着每个会话都将打开该游标数。游标根据需要打开。如果您的某个应用程序有光标泄漏,即使OPEN_CURSORS设置为高,它也会最终显示。

要查看是否已将OPEN_CURSORS设置得足够高,请监视v $ sesstat以获取当前打开的最大游标数。如果您的会话运行接近限制,则增加OPEN_CURSORS的值。

SQL> select max(a.value) as highest_open_cur, p.value as max_open_cur
2> from v$sesstat a, v$statname b, v$parameter p
3> where a.statistic# = b.statistic# 
4> and b.name = 'opened cursors current'
5> and p.name= 'open_cursors'
6> group by p.value;

HIGHEST_OPEN_CUR MAX_OPEN_CUR
---------------- ------------
            1953         2500

HIGHEST_ OPEN CUR是实际打开的cursors 的最大值,MAX_OPEN_ CUR是参数Open_cursors的设定值,如果二者太接近,甚至触发ORA一01000错误,那么你就应该调大参数Open_cursors的设定值。如果问题依旧没有解决,盲目增大Open_cursors也是不对的,这个时候你得检查应用程序的代码是否合理,比如说应用程序是否打开了游标,却没有在它完成工作后没有及时关闭。以下语句可以帮助你确定导致游标漏出的会话:

select a.value, s.username, s.sid, s.serial#
from   v$sesstat a, v$statname b, v$session s
where  a.statistic# = b.statistic# and s.sid=a.sid
and    b.name = 'opened cursors current';

在增加OPEN_CURSORS的值之后,请密切注意v $ sesstat以查看当前打开的游标当前是否持续增加。如果您有一个应用程序会话,其打开的游标当前总是增加以赶上OPEN_CURSORS,那么您的应用程序代码中可能会出现游标泄漏,即您的应用程序正在打开游标而在完成时不关闭游标。应用程序开发人员需要查看代码,找到保持打开的游标并关闭它们。

监视会话CURSOR CACHE(SESSION_CACHED_CURSORS)

v $ sesstat还提供统计信息来监视每个会话在其会话游标缓存中的游标数。

--session cached cursors, by session
select a.value, s.username, s.sid, s.serial#
from v$sesstat a, v$statname b, v$session s
where a.statistic# = b.statistic# and s.sid=a.sid
and b.name = 'session cursor cache count' ;

session_cached_cursors的值也不是越大越好,我们可以通过下面两条语句得出合理的设置。

     SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME LIKE '%cursor%';  
      
    NAME                                                                  VALUE  
    ---------------------------------------------------------------- ----------  
    opened cursors cumulative                                             15095  
    opened cursors current                                                   34  
    session cursor cache hits                                             12308  
    session cursor cache count                                              775  
    cursor authentications                                                  324  
      
   SELECT NAME, VALUE FROM V$SYSSTAT WHERE NAME LIKE '%parse%';  
      
    NAME                                                                  VALUE  
    ---------------------------------------------------------------- ----------  
    parse time cpu                                                          332  
    parse time elapsed                                                     1190  
    parse count (total)                                                    9184  
    parse count (hard)                                                     1031  
    parse count (failures)                                                    3  

session cursor cache hits就是系统在高速缓存区中找到相应cursors的次数,parse count(total)就是总的解析次数,二者比值越高,性能越好。如果比例比较低,并且有较多剩余内存的话,可以考虑加大该参数

您还可以通过查询v $ open_cursor直接查看会话游标缓存中的内容。v $ open_cursor按SID列出会话缓存游标,并包含语句的前几个字符和sql_id,因此您可以实际告诉游标的用途。

select c.user_name, c.sid, sql.sql_text
from   v$open_cursor c, v$sql sql
where  c.sql_id=sql.sql_id          -- for 9i and earlier use: c.address=sql.address
and    c.sid=&sid;

调整会话游标缓存(SESSION_CACHED_CURSORS)您可以查询V $ SYSSTAT以确定会话游标缓存对于数据库实例是否足够大。

要调整会话游标缓存:

如果您选择使用SESSION_CACHED_CURSORS来帮助不断关闭和重新打开游标的应用程序,则可以通过v $ sesstat中的另外两个统计信息来监视其有效性。统计信息“会话游标缓存命中”反映了在会话游标缓存中找到会话发送用于解析的语句的次数,这意味着它不必重新分析,并且您的会话不必搜索库缓存中的它。您可以将其与统计信息“parse count(total)”进行比较; 从“解析计数(总计)”中减去“会话游标缓存命中数”,以查看实际发生的解析数。

1. 确定特定会话中当前缓存的游标数量。

例如,为会话35输入以下查询:

SQL> SELECT a.value curr_cached, p.value max_cached,
2 s.username, s.sid, s.serial#
3 FROM v$sesstat a, v$statname b, v$session s, v$parameter2 p
4 WHERE a.statistic# = b.statistic# and s.sid=a.sid and a.sid=&sid
5 AND p.name='session_cached_cursors'
6 AND b.name = 'session cursor cache count';
Enter value for sid: 35
old 4: WHERE a.statistic# = b.statistic# and s.sid=a.sid and a.sid=&sid
new 4: WHERE a.statistic# = b.statistic# and s.sid=a.sid and a.sid=35

CURR_CACHED MAX_CACHED USERNAME SID SERIAL#
----------- ---------- -------- --- -------
         49         50 APP       35     263

前面的结果显示当前为会话35缓存的游标数接近最大值。

2. 找到在会话游标缓存中找到游标的解析调用的百分比。

例如,为会话35输入以下查询:

SQL> SELECT cach.value cache_hits, prs.value all_parses,round((cach.value/prs.value)*100,2) as "% found in cache"
FROM  v$sesstat cach, v$sesstat prs, v$statname nm1, v$statname nm2
WHERE cach.statistic# = nm1.statistic#
AND   nm1.name = 'session cursor cache hits'
AND   prs.statistic#=nm2.statistic#
AND   nm2.name= 'parse count (total)'
AND   cach.sid= &sid and prs.sid= cach.sid;

Enter value for sid: 35
old 8: AND cach.sid= &sid and prs.sid= cach.sid
new 8: AND cach.sid= 35 and prs.sid= cach.sid

CACHE_HITS ALL_PARSES % found in cache
---------- ---------- ----------------
        34        700             4.57

前面的结果表明,会话35的会话游标缓存中的命中数与解析总数相比较低。

3.当以下语句为真时,请考虑增加SESSION_CURSOR_CACHE:
*会话游标缓存计数接近最大值。
*会话游标缓存命中的百分比相对于总分析而言较低。
*应用程序重复进行相同查询的解析调用。

在此示例中,将SESSION_CURSOR_CACHE设置为100可能有助于提高性能。

如果会话游标缓存计数最大化,则session_cursor_cache_hits与所有解析相比较低,并且您怀疑应用程序重复提交相同的查询以反复解析,然后增加SESSION_CURSOR_CACHE_COUNT可能有助于解决锁存器争用并略微提升性能。请注意,如果您的应用程序没有重复提交相同的查询以便重复解析,那么session_cursor_cache_hits将会很低,并且会话游标缓存计数可能会被最大化,但是按会话缓存游标将完全没有帮助。例如,如果您的应用程序使用了大量不可共享的SQL,则提高此参数将无济于事。

使用下面的sql判断'session_cached_cursors' 的使用情况。如果使用率为100%则增大这个参数值

select
'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') and
s.statistic# = n.statistic#
group by
s.sid
),
( select
value
from
v$parameter
where
name = 'open_cursors'
)

当我们执行一条sql语句的时候,我们将会在shared pool产生一个library cache object,cursor就是其中针对于sql语句的一种library cache object.另外我们会在pga有一个cursor的拷贝,同时在客户端会有一个statement handle,这些都被称为cursor,在v$open_cursor里面我们可以看到当前打开的cursor和pga内cached cursor.

session_cached_cursor这个参数限制了在pga内session cursor cache list的长度,session cursor cache list是一条双向的lru链表,当一个session打算关闭一个cursor时,如果这个cursor的parse count超过3次,那么这个cursor将会被加到session cursor cache list的MRU端.当一个session打算parse一个sql时,它会先去pga内搜索session cursor cache list,如果找到那么会把这个cursor脱离list,然后当关闭的时候再把这个cursor加到MRU端.session_cached_cursor提供了快速软分析的功能,提供了比soft parse更高的性能.
 

猜你喜欢

转载自blog.csdn.net/j_ychen/article/details/100988433