#Oracle #参数 # open_cursors #ORA-01000
在 Oracle 数据库的众多参数中,open_cursors是一个对应用程序性能和资源管理有着重要影响的参数。它直接关系到数据库与应用程序之间游标资源的使用与分配,合理配置open_cursors参数,能够避免应用程序出现游标相关的错误,提升数据库的整体运行效率。本文将深入介绍open_cursors参数,并通过实际测试过程展示其对数据库性能的影响。
一、open_cursors 参数说明
1. 基本概念
open_cursors参数用于设置单个会话中可以同时打开的游标数量上限。游标是 Oracle 数据库处理 SQL 语句的一个重要机制,它为应用程序提供了一种对查询结果集进行逐行处理的方式。当应用程序执行SELECT、INSERT、UPDATE、DELETE等 SQL 语句时,Oracle 会隐式或显式地打开游标,以管理数据的读取和操作。
2. 作用与影响
如果应用程序在一个会话中打开的游标数量超过open_cursors参数设置的值,Oracle 将抛出ORA-01000: maximum open cursors exceeded错误,导致应用程序运行异常。另一方面,open_cursors参数值设置过大,会占用过多的系统资源,增加内存开销,影响数据库的整体性能;设置过小,则可能无法满足应用程序的正常需求,限制应用程序的并发处理能力。因此,根据应用程序的实际需求和数据库负载情况,合理设置open_cursors参数至关重要。
3. 动态调整
open_cursors是一个动态参数,这意味着在数据库运行过程中,可以通过ALTER SYSTEM或ALTER SESSION语句对其进行修改,而无需重启数据库实例。例如,要将全局的open_cursors参数值设置为 1000,可以使用以下语句:
ALTER SYSTEM SET open_cursors = 1000 SCOPE = BOTH;
若只想在当前会话中修改该参数值,则使用:
ALTER SESSION SET open_cursors = 1000;
二、什么是打开的游标
跟踪一下v$open_cursor底层调用的基表
select view_definition from v$fixed_view_definition where view_name like 'V$OPEN_CURSOR'
select SADDR,
SID,
USER_NAME,
ADDRESS,
HASH_VALUE,
SQL_ID,
SQL_TEXT,
LAST_SQL_ACTIVE_TIME,
SQL_EXEC_ID,
CURSOR_TYPE,
CHILD_ADDRESS,
CON_ID
from GV$OPEN_CURSOR
where inst_id = USERENV('Instance')
select view_definition from v$fixed_view_definition where view_name like 'GV$OPEN_CURSOR';
select inst_id,
kgllkuse,
kgllksnm,
user_name,
kglhdpar,
kglnahsh,
kgllksqlid,
kglnaobj,
kgllkest,
decode(kgllkexc, 0, to_number(NULL), kgllkexc),
kgllkctp,
kgllkhdl,
con_id
from x$kgllk
where kglhdnsp = 0
and kglhdpar != kgllkhdl
x$kgllk是library cache lock相关的基表,那我们可以得到结论:只要SQL上加了library cache lock,就是一个打开的游标。那什么场景下,SQL会加上library cache lock,我们在后面的知识体系中再介绍。
三、游标相关的报错ORA-01000: maximum open cursors exceeded
3.1、报错原因
ORA-01000错误的核心原因是在单个数据库会话中,打开的游标数量超过了open_cursors参数所设定的上限。游标是 Oracle 处理 SQL 语句时用于管理数据操作的重要机制,无论是执行简单的查询语句,还是复杂的事务操作,都会涉及到游标。当应用程序频繁执行 SQL 语句,却没有及时关闭不再使用的游标,就会导致游标不断累积。一旦累积数量突破open_cursors的限制,Oracle 数据库就会抛出ORA-01000错误。
此外,应用程序代码中存在逻辑缺陷,例如在循环中重复打开游标却未正确释放,或者在事务处理过程中异常终止但游标未关闭,也会造成游标资源过度占用,进而触发该错误。同时,若open_cursors参数设置不合理,无法满足应用程序实际的游标使用需求,即使应用程序代码正常,也可能出现此报错。
3.2 报错影响
ORA-01000错误会直接中断应用程序的正常运行。当应用程序执行到引发该错误的 SQL 语句时,会立即停止执行,并将错误信息返回给调用端。这会导致用户操作失败,严重影响业务流程的连续性,降低用户体验。
从数据库层面来看,过多未关闭的游标会占用大量的内存资源,导致数据库内存使用效率下降。如果多个会话同时出现游标超标的情况,还可能引发数据库性能急剧恶化,甚至导致数据库响应缓慢、服务不可用等严重后果。长期积累的未关闭游标还可能造成内存碎片,进一步影响数据库的稳定性和性能。
3.3 故障模拟
1、查看当前的open_cursor参数
SYS@pdb1> show parameter open_cursor
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
open_cursors integer 300
2、新开一个连接
APPS@pdb1> select distinct sid from v$mystat;
SID
----------
448
3、打开300个游标,不关闭
declare
msql varchar2(2000);
mcur number;
mstat number;
begin
for i in 1..300 loop
mcur := dbms_sql.open_cursor;
msql := 'select object_id from apps.t1 where object_id='||to_char(i);
dbms_sql.parse(mcur,msql,dbms_sql.native);
mstat :=dbms_sql.execute(mcur);
end loop;
end;
/
4、查看SID=448正在打开的游标
SYS@pdb1> select count(1)
2 from v$open_cursor t
3 where t.sid = '448'
4 and t.cursor_type = 'OPEN-RECURSIVE';
COUNT(1)
----------
299
3.4 排查思路
(1) 检查open_cursors参数设置
使用以下 SQL 语句查询当前数据库实例的open_cursors参数值:
SELECT valueFROM v$parameter WHERE name = 'open_cursors';
对比该参数值与应用程序实际的游标使用需求,判断是否设置过小。若应用程序存在大量并发操作或复杂的 SQL 执行逻辑,可能需要适当增大该参数值。
(2)分析应用程序代码
仔细审查应用程序中涉及数据库操作的代码,重点检查游标打开和关闭的逻辑。查看是否存在循环中重复打开游标却未关闭的情况,或者事务回滚、异常处理时游标未正确释放的问题。对于使用连接池的应用,确保连接池配置合理,连接归还时游标已全部关闭。
(3)监控数据库会话
通过查询v$open_cursor视图,获取当前所有打开的游标信息,找出当前打开游标最多的会话:
SELECT S.USERNAME, A.VALUE,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'
order by value desc;
找出游标数量异常多的会话,结合应用程序业务逻辑,判断是否存在不合理的游标使用。
3.5 故障解决方案
解决这个问题,本质就是要关闭掉打开的游标,可以通过以下方法:
1、退出执行会话的窗口
2、KILL掉会话
1、查看会话打开的cursor数
SYS@pdb1> select sid,count(1)
from v$open_cursor t
where t.cursor_type = 'OPEN-RECURSIVE'
group by sid;
SID COUNT(1)
---------- ----------
422 2
448 298
440 10
2、查看SID=448的PID
SYS@pdb1> select spid from v$session s ,v$process p where s.paddr=p.addr and sid=448;
SPID
------------------------
24808
3、kill掉进程
[oracle@database ~]$ ps -ef|grep 24808
oracle 24808 1 0 09:53 ? 00:00:00 oracleORCLCDB (LOCAL=NO)
oracle 24848 7583 0 09:56 pts/2 00:00:00 grep --color=auto 2480
[oracle@database ~]$ kill -9 24808
4、查看会话打开的游标
SYS@pdb1> select sid,count(1)
2 from v$open_cursor t
3 where t.cursor_type = 'OPEN-RECURSIVE'
4 group by sid;
SID COUNT(1)
---------- ----------
422 2
440 10
3、KILL应用端连接进程
3.6 优化方案
1. 调整open_cursors参数
如果确定是参数设置过小导致的错误,可以通过以下语句调整open_cursors参数值:
-- 全局修改
ALTER SYSTEM SET open_cursors = [新值] SCOPE = BOTH;
-- 仅修改当前会话
ALTER SESSION SET open_cursors = [新值];
修改参数值时,需综合考虑数据库服务器的硬件资源和应用程序的实际需求,避免设置过大影响系统性能。可以通过查看OPEN_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;
2. 优化应用程序代码
修正应用程序中游标使用的逻辑错误,确保在游标使用完毕后及时关闭。对于复杂的事务处理和循环操作,合理规划游标的打开和关闭时机。例如,在 Java 应用中,使用try-with-resources语句自动关闭游标:
try (Connection connection = DriverManager.getConnection(url, user, password);
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery("SELECT * FROM employees")) {
while (resultSet.next()) {
// 处理结果集
}
} catch (SQLException e) {
e.printStackTrace();
}
3. 加强数据库监控
建立完善的数据库监控机制,定期检查open_cursors参数的使用情况和游标资源占用情况。通过设置告警阈值,当游标数量接近或超过open_cursors参数值时,及时发出告警,以便运维人员提前采取措施,避免ORA-01000错误的发生。
四、 总结
通过对比不同的使用场景,可以发现:
- 当使用默认参数值或参数值设置较小时,测试程序在打开一定数量游标后,会出现ORA-01000错误,导致程序无法正常执行,影响应用程序的稳定性。
- 随着open_cursors参数值的增大,程序能够顺利执行完所有游标操作,执行时间可能会有所缩短,因为减少了因游标数量限制导致的错误处理和重新连接等额外开销。但同时,数据库的内存使用量会相应增加,因为更多的游标需要占用内存资源。
- 在超出参数值测试场景中,明确验证了open_cursors参数对游标数量的限制作用,当游标数量超过设置值时,会及时抛出错误,提醒开发人员需要调整参数或优化应用程序中游标的使用。
综上所述,open_cursors参数在 Oracle 数据库中起着关键的作用,合理配置该参数能够有效提升应用程序的性能和稳定性。在实际应用中,需要根据应用程序的并发量、业务逻辑以及数据库的硬件资源情况,综合考虑并动态调整open_cursors参数值,以达到最佳的运行效果。
🚀 更多数据库干货,欢迎关注【安呀智数据坊】
如果你觉得这篇文章对你有帮助,欢迎点赞 👍、收藏 ⭐ 和留言 💬 交流,让我知道你还想了解哪些数据库知识!
📬 想系统学习更多数据库实战案例与技术指南?
📊 实战项目分享
📚 技术原理讲解
🧠 数据库架构思维
🛠 工具推荐与实用技巧
立即关注,持续更新中 👇