暂无图片
暂无图片
2
暂无图片
暂无图片
暂无图片

Session Cursor概念说明及ORA-01000错误的处理方式

原创 王小那个鑫 2022-03-03
1247

一 session cursor

Session Cursor与Session是一一对应的,不同Session的Session Cursor之间没法共享,这与Shared Cursor有本质区别;

每个Session Cursor在使用的过程中都至少会经历一次Open、Parse、Bind、Execute、Fetch和Close中的一个或多个阶段,用过的Session Cursor不一定会缓存在对应的Session的PGA中,只有SESSION_CACHED_CURSORS>0的时候,才会缓存在PGA中;

Session Cursor是以哈希表的方式缓存在PGA中,意味着Oracle会通过相关的哈希运算来存储和访问在当前Session的PGA中的对应Session Cursor。这种访问机制实际上和Shared Cursor是一样的,简单理解:Oracle根据SQL文本的哈希值去PGA中的相应Hash Bucket中找匹配的Session Cursor。

Oracle在解析和执行目标SQL时,会先去当前的Session的PGA中找是否存在匹配的缓存Session Cursor。

当Oracle第一次解析和执行目标SQL时(硬解析),当前Session的PGA中肯定不存在匹配Session Cursor,这时Oracle会新生成一个Session Cursor和一对Shared Cursor(即Parent Cursor和Child Cursor),这其中的Shared Cursor会存储,能被所有Session共享、重用(比如标上SQL的解析树、执行计划等),而Session Cursor则会经历一次Open、Parse、Bind、Execute、Fetch和Close中的一个或多个阶段。

对于Oracle 11g之前的版本,在缓存Session Cursor的哈希表的对应Hash Bucket中,Oracle会存储目标SQL对应的Parent Cursor的库缓存对象句柄地址,这意味着Oracle已经建立了目标SQL的Session Cursor与其Parent Cursor之间的联系,即Oracle可以通过Session Cursor找到对应的Parent Current,进而就可以找到对应Child Cursor中目标SQL的解析树和执行计划,然后Oracle就可以按照这个解析树和执行计划来执行目标SQL了。

二 相关参数

OEPN_CURSORS: 表示每个session(会话)最多能同时打开多少个cursor

SESSION_CACHED_CURSORS: 表示每个session(会话)最多可以缓存多少个关闭掉的cursor


从上图可以看出来两个问题:

1)open_cursors和session_cached_cursors没有太大的相关;

2)两个参数都会让后续相同的sql语句不在打开游标,从而避免软解析过程来提供应用程序的效率;

三 相关错误及排查思路(参考Doc ID 1477783.1)

ORA-01000: 超出打开游标的最大数

当open_cursors设置过小的时候则可能产生ORA-01000错误;如果设置太大,则可能会由于cursor不释放,导致内存消耗;

SELECT max(a.value) as highest_open_cur, p.value as max_open_cur FROM v$sesstat a, v$statname
b, v$parameter p WHERE a.statistic# = b.statistic# and b.name = 'opened cursors current' and
p.name= 'open_cursors' group by p.value;

highest_open_cur   max_open_cur
---------------- --------------------
47               300
复制

第一个参数表示当前系统中打开最大cursor参数;

第二个参数则等于open_cursors参数;

因此,当第一个参数和第二个参数的数量接近的时候,则可能会触发该错误;

此时错误原因则可能有两个:

1.程序发生cursor泄露,在应用程序代码中打开cursor后,未进行关闭;

2.数据库业务量巨大,open_cursors参数过小;


当出现ora-01000时,我们可以通过以下sql查出造成该问题的会话:

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' and s.username is not null;
复制

根据查询出的value超过open_cursors参数的会话,执行以下sql则可以找出当前造成该问题的sql语句:

select sid ,sql_text, user_name, count(*) as "OPEN CURSORS" from v$open_cursor where sid in
($SID) group by sid ,sql_text, user_name;

或者:

SELECT s.machine, oc.user_name, oc.sql_text, count(1) FROM v$open_cursor oc,v$session s
WHERE oc.sid = s.sid and user_name != 'SYS' GROUP BY user_name,sql_text, machine HAVING
COUNT(1) > 5 ORDER BY count(1) DESC;
复制

找出造成问题的sql后,我们的处理方式则可以分为两个:

1.如果是由于参数过小导致,则可以直接修改open_cursors参数,该参数可以在线修改

alter system set open_cursors=2000 scope=both sid='*';
复制

2.如果由于程序代码出现未关闭的情况,则可以将查询出来的sql反馈开发,由开发人员进行代码排查。


另外我们也可以通过event的设置进行事件跟踪,找到产生该问题的原因:

alter system set events '1000 trace name errorstack level 3';
alter system set events '1000 trace name errorstack off';
复制

五 相关视图

v$open_cursor

v$sesstat

v$namestat,其中 name = 'opened cursors current'

最后修改时间:2022-03-04 15:31:42
「喜欢这篇文章,您的关注和赞赏是给作者最好的鼓励」
关注作者
2人已赞赏
【版权声明】本文为墨天轮用户原创内容,转载时必须标注文章的来源(墨天轮),文章链接,文章作者等基本信息,否则作者和墨天轮有权追究责任。如果您发现墨天轮中有涉嫌抄袭或者侵权的内容,欢迎发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论