oracle - Oracle 19c Open_cursor 超出问题
问题描述
我们在 Oracle 10g 和 19c 中存在相同的存储过程,具有相同的数据集和设置。该过程执行了许多数据获取和操作。当我们使用相同的数据集(比如说 10000 条记录)执行时,它在 10g 中运行良好,时间更短,但在 19c 中需要很长时间,一段时间后它会抛出“超出打开游标限制”错误。我们从两个数据库中对 OPEN_CURSOR 和 CACHED_CURSOR 大小进行了基本比较,这是相同的。
我们可以从服务器端比较哪些其他参数或设置以解决此问题?
解决方案
我无法告诉您是什么导致了最大打开游标问题,但我告诉您如何通过使用GV$OPEN_CURSOR
.
如果幸运的话,您可以通过一个简单的查询立即发现问题,该查询计算每个会话的打开游标数。以下查询中有很多列,使用 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;
/
推荐阅读
- reactjs - gatsbyJS中graphQL查询和页面组件的集成测试
- ios - 如何让 RealmSwift 与 Xcode 11 一起工作?
- java - eclipse中的条件断点不适用于局部变量?
- android - Android4.0是否支持Android复选框属性“android:button”?
- function - Octave中以向量为参数的函数
- migration - AndroidX FrameLayout layout_heightPercent 属性未找到错误
- java - Sonarqube 不接受我的测试,但它在我的 Eclipse 中有效
- spring - 春季单元测试存储库保存不起作用
- jenkins - 如何使用 Jenkins 基于代码更改构建阶段?
- oracle - 在 SQL 上使用简单的“CREATE TABLE”似乎不起作用,更多信息