Oracle 19c Open_cursor 超出问题

Posted

技术标签:

【中文标题】Oracle 19c Open_cursor 超出问题【英文标题】:Oracle 19c Open_cursor exceeded issue 【发布时间】:2021-01-16 13:27:48 【问题描述】:

我们在 Oracle 10g 和 19c 中存在相同的存储过程,具有相同的数据集和设置。 该过程执行了许多数据获取和操作。 当我们使用相同的数据集(比如说 10000 条记录)执行时,它在 10g 中运行良好,时间更短,但在 19c 中需要很长时间,一段时间后它会抛出“超出打开游标限制”错误。 我们对两个数据库的 OPEN_CURSOR 和 CACHED_CURSOR 大小进行了基本比较。

我们还可以从服务器端比较哪些参数或设置以解决此问题?

【问题讨论】:

该错误实际上总是表明您的应用程序代码存在游标泄漏,因此通常只能通过修复您的应用程序来修复它。你可以提高open_cursors 参数,但如果你有游标泄漏,那只会延迟错误而不是阻止它。 以10000条记录为起点,尽可能根据这个数量的记录进行批量处理。 【参考方案1】:

我无法告诉您导致最大打开游标问题的原因,但我告诉您如何通过使用GV$OPEN_CURSOR 识别相关会话和 SQL 语句来找到原因。

如果幸运的话,您可以通过计算每个会话的打开游标数的简单查询立即找到问题。下面的查询中有很多列,使用 IDE 可以轻松浏览所有数据。根据我的经验,只需查看 USER_NAME 和 SQL_TEXT 等列就足以确定罪魁祸首。

select count(*) over (partition by inst_id, sid) cursors_per_session, gv$open_cursor.*
from gv$open_cursor
order by cursors_per_session desc, inst_id, sid;

请记住,该视图中可能会出现许多奇怪的查询,这些查询可能会使计数超出您的预期。对于所有递归和缓存查询,“无聊”会话使用 50 个游标并不罕见。您正在寻找具有数百个打开游标的会话。 (除非有人愚蠢地将参数值降低到默认值以下。)

不幸的是,GV$OPEN_CURSOR 不包含历史数据,如果在快速打开大量游标的紧密循环中出现异常,这些问题可能会快速启动和停止。下面的 PL/SQL 块一直运行,直到它找到具有大量打开游标的会话、存储数据并退出。这个 PL/SQL 块很昂贵,并且会用完整个会话的处理等待正确的时刻,所以只使用一次就可以找到问题。

--Create table to hold the results.
create table too_many_cursors as
select 1 cursors_per_session, gv$open_cursor.*
from gv$open_cursor
where 1 = 0;


--Write the open cursor data when a session gets more than N open cursors.
declare
    v_open_cursor_threshold number := 50;
    v_count number;
begin
    --Loop forever until the problem is found.
    loop
        --Count the largest numbe of open cursors.
        select max(the_count)
        into v_count
        from
        (
            select count(*) the_count
            from gv$open_cursor
            group by inst_id, sid
        );

        --If the threshold is reached, write the data, commit it, and quit the program.
        if v_count >= v_open_cursor_threshold then

            insert into too_many_cursors
            select *
            from
            (
                select count(*) over (partition by inst_id, sid) cursors_per_session, gv$open_cursor.*
                from gv$open_cursor
            )
            where cursors_per_session >= v_open_cursor_threshold;
            
            commit;
            
            exit;
        end if;
        
    end loop;
end;
/


--Your problem should now be in this table:
select * from too_many_cursors;

如果你想测试监控,可以使用下面的PL/SQL块打开大量游标。

--Open a large number of cursors in and wait for 20 seconds.
--(Done by creating a dynamic PL/SQL block with many "open" commands with a "sleep" at the end.
declare
    v_number_of_open_cursors number := 200;
    v_declarations clob;
    v_opens clob;
    v_sql clob;
begin
    for i in 1 .. v_number_of_open_cursors loop
        v_declarations := v_declarations || 'v_cursor'|| i ||' sys_refcursor;' || chr(10);
        v_opens := v_opens || 'open v_cursor' || i || ' for select * from dual;';
    end loop;

    v_sql :=
        'declare '||chr(10)||v_declarations||chr(10)||
        'begin'||chr(10)||v_opens||chr(10)||
        'dbms_lock.sleep(20);'||chr(10)||'end;';

    --Print for debugging.
    --dbms_output.put_line(v_sql);

    execute immediate v_sql;
end;
/

【讨论】:

以上是关于Oracle 19c Open_cursor 超出问题的主要内容,如果未能解决你的问题,请参考以下文章

Oracle19c基本操作

安装oracle19c提示少dell

oracle10客户端如何连接19c

18c 与 19c 上的 Oracle 编号问题

Oracle 19c - 手动升级到 Non-CDB Oracle Database 19c 的完整核对清单 (Doc ID 2577572.1)

Oracle 19c - 手动升级到 Non-CDB Oracle Database 19c 的完整核对清单 (Doc ID 2577572.1)