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更高的性能.
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章