Oracle的打开游标(OPEN_CURSORS)

一、OPEN_CURSORS 概述

OPEN_CURSORS 指定会话一次可以拥有的打开游标(私有 SQL 区域的句柄)的最大数量。可以使用此参数来防止会话打开过多的游标。

OPEN_CURSORS参数说明

|---------|--------------|
| 特性 | 描述 |
| 参数类型 | Integer |
| 默认值 | 50 |
| 修改方式 | ALTER SYSTEM |
| PDB级别修改 | 是 |
| 参数范围 | 0 到 65535 |
| 初始化参数 | 是 |

将 OPEN_CURSORS 的值设置得足够高非常重要,以防止应用程序耗尽打开的游标。不同的应用程序的数量会有所不同。假设会话未打开由 OPEN_CURSORS 指定的游标数量,则将此值设置为高于实际需要的值不会增加任何开销。

二、什么是OPEN_CURSORS

对oracle来说,什么是打开的游标

查看v$open_cursor定义

cpp 复制代码
 select VIEW_DEFINITION from v$fixed_view_definition where view_name='GV$OPEN_CURSOR';
VIEW_DEFINITION
--------------------------------------------------------------------------------
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

可以看到vopen_cursor的基础是xkgllk,这个一个关于Libraray Cache Lock的视图。也就是说,只要SQL上持有了Libraray Cache Lock,它就是一个打开的游标。

三、打开游标的内存释放规则

当某个SQL被缓存时,会持有Libraray Cache Lock,其相关的内存不会被释放或覆盖。

通过实验证明

3.1 将目标SQL游标缓存

会话1

cpp 复制代码
 sqlplus sys/oracle@pdb1 as sysdba

select p.spid,s.sid,s.serial# from v$process p,v$session s where p.addr=s.paddr and  sid=(select distinct sid from v$mystat);

SPID                            SID    SERIAL#
------------------------ ---------- ----------
35997                            22       3850

--执行3次
select object_name from test1 where object_id=9;
select object_name from test1 where object_id=9;
select object_name from test1 where object_id=9;
select object_name from test1 where object_id=9;

3.2 查看SQL对应的游标状态

会话2

cpp 复制代码
select sid,CURSOR_TYPE from v$open_cursor where SQL_TEXT='select object_name from test1 where object_id=9';

       SID CURSOR_TYPE
---------- ----------------------------------------------------------------
        22 SESSION CURSOR CACHED

3.3 查看SQL对应的libraray cache lock

会话2

cpp 复制代码
conn / as sysdba


select kglhdadr,kglhdlmd,kglhdpmd,kglobhs0,kglobhs6 from x$kglob where kglnaobj like 'select object_name from test1 where object_id=9';

KGLHDADR           KGLHDLMD   KGLHDPMD   KGLOBHS0   KGLOBHS6
---------------- ---------- ---------- ---------- ----------
00000000693483A8          1          0       4072      12144
000000006936D740          1          0       4072          0

SQL> 

可以看到,父游标句柄和子游标句柄上持有NULL模式的libraray cache lock

3.4 刷新共享池

刷新之后查看该sql内存占用情况

cpp 复制代码
conn / as sysdba

alter system flush shared_pool;

select kglhdadr,kglhdlmd,kglhdpmd,kglobhs0,kglobhs6 from x$kglob where kglnaobj like 'select object_name from test1 where object_id=9';

KGLHDADR           KGLHDLMD   KGLHDPMD   KGLOBHS0   KGLOBHS6
---------------- ---------- ---------- ---------- ----------
00000000693483A8          1          0          0          0
000000006936D740          1          0       4072          0

可以看到,当某个游标会缓存的情况下,父游标句柄和子游标的空间未被释放,但子游标的heap 0和heap 6空间被释放。

四、如何释放未被关闭的游标内存

从上面实验可以看出,刷新共享池,并不能有效释放游标所占用的空间。方法只有一个,那就是将游标关闭。我们无法直接关闭应用程序中已经打开的游标,那只能选择kill掉某个游标所对应的进程或会话。

kill进程

cpp 复制代码
kill -9 35997

以下操作均在cdb下

查看游标缓存情况

cpp 复制代码
select sid,CURSOR_TYPE from v$open_cursor where SQL_TEXT='select object_name from test1 where object_id=9';
no rows selected

查看游标内存使用情况

cpp 复制代码
select kglhdadr,kglhdlmd,kglhdpmd,kglobhs0,kglobhs6 from x$kglob where kglnaobj like 'select object_name from test1 where object_id=9';

KGLHDADR           KGLHDLMD   KGLHDPMD   KGLOBHS0   KGLOBHS6
---------------- ---------- ---------- ---------- ----------
0000000077E2C910          0          0          0          0
0000000077EFE3F8          0          0       4072          0

再次刷新共享池,游标对应的所有内存被释放。

cpp 复制代码
alter system flush shared_pool;

select kglhdadr,kglhdlmd,kglhdpmd,kglobhs0,kglobhs6 from x$kglob where kglnaobj like 'select object_name from test1 where object_id=9';

no rows selected

五、总结

由此可见,被缓存的游标并不是越多越好,过多缓存游标会占用大量的共享池空间,严重时会导致ORA-4031问题,关于ORA-4031报错,我们会在下一章节剖析。

相关推荐
李兆龙的博客几秒前
从一到无穷大 #70 从 LR 图 PEC 到InfluxQL兼容性差分测试方法论与工程实践
数据库·功能测试·oracle
爱学习的小囧3 分钟前
ESXi 开启 Secure Boot 后驱动签名验证失败完整处置教程:合规修复与临时测试方案全解
服务器·数据库·esxi·虚拟化
weixin_5689960612 分钟前
如何用 IndexedDB 存储从 API 获取的超大列表并实现二级索引
jvm·数据库·python
APIshop14 分钟前
小红书笔记视频详情接口深度解析:smallredbook.item_get_video_pro
数据库·笔记·音视频
空中海16 分钟前
Redis 从零到精通:9大数据结构 × 11个高频工程实战场景完全手册
数据结构·数据库·redis
qiuyunoqy16 分钟前
MySQL - 2
数据库·mysql
2301_7751481520 分钟前
如何授权AWR报告生成_GRANT SELECT ANY DICTIONARY诊断权限
jvm·数据库·python
空中海32 分钟前
Redis 专家实战:生产架构设计 × 容量规划 × 安全治理 × 37道高频面试题全解
数据库·redis·安全
地球资源数据云1 小时前
1951-2025年中国逐年1千米逐月总降水量区域统计数据集_年表_县
大数据·数据结构·数据库·数据仓库·人工智能
l1t1 小时前
DeepSeek v4辅助生成的单文件SQL查询示例页面
javascript·数据库·sql