Oracle的缓存会话游标

会话游标缓存(session cursor cache)包含 SQL 和 PL/SQL(包括递归 SQL)的关闭会话游标。此缓存对于使用 Oracle Forms 的应用程序非常有用,因为从一个表单切换到另一个表单会关闭与第一个表单关联的所有会话游标。如果应用程序对同一组 SQL 语句重复发出解析调用,则重新打开会话游标可能会降低性能。通过重用游标,数据库减少了解析时间,从而加快了整体执行时间。

一、关于会话游标缓存

会话游标表示共享子游标的实例,该子游标存储在共享池中,用于特定会话。每个会话游标都存储对其已实例化的子游标的引用。

1.1 缓存机制

Oracle 数据库检查库缓存以确定是否对给定语句发出了三次以上的解析请求。如果游标已关闭 3 次,则 Oracle 数据库假定应缓存与该语句关联的会话游标,并将游标移动到会话游标缓存中。

通过一个实验来验证会话游标缓存

窗口1

cpp 复制代码
select sid from v$mystat where rownum<2;



      SID

----------

       35



select object_name from t1 where object_id=9;



OBJECT_NAME

--------------------------------------------------------------------------------

I_FILE#_BLOCK#



SQL>

窗口2

cpp 复制代码
set linesize 1000
col cursor_type for a30
select sid,sql_id,last_sql_active_time,cursor_type from v$open_cursor where sid=35 and sql_text like 'select object_name from t1 where object_id=9';
       SID SQL_ID        LAST_SQL_ CURSOR_TYPE
---------- ------------- --------- ------------------------------
        35 gktg9sdjkxh6p 28-NOV-24 OPEN

当窗口1中的SQL执行3次,第3次执行时,状态发生了改变,从open变为SESSION CURSOR CACHED

cpp 复制代码
 SID SQL_ID        LAST_SQL_ CURSOR_TYPE

---------- ------------- --------- ------------------------------

       35 gktg9sdjkxh6p 28-NOV-24 SESSION CURSOR CACHED

同一会话解析 SQL 语句的后续请求将在数组中搜索指向共享游标的指针。如果找到该指针,则数据库取消引用该指针以确定共享游标是否存在。为了重用缓存中的游标,缓存管理器会检查游标的缓存状态是否与当前会话和系统环境匹配。

注意:重用缓存游标仍会被认为是硬解析,即使它不是硬解析。

1.2 会话游标老化算法

LRU 算法会删除会话游标缓存中的条目,以便在需要时为新条目腾出空间。缓存还使用基于时间的内部算法来老化已空闲一定时间的游标。

二、启用会话游标缓存

2.1 会话游标相关参数

以下初始化参数与会话游标缓存有关:

  • SESSION_CACHED_CURSORS

该参数设置每个会话缓存的关闭游标的最大数量。默认值为 50。使用此参数可以为在同一会话中重复执行的语句重用缓存中的游标。

  • OPEN_CURSORS

该参数指定一个会话可以同时打开的游标的最大数量。例如,如果其值设置为 1000,则每个会话一次最多可以打开 1000 个游标。

这些参数是独立的。例如,您可以将 SESSION_CACHED_CURSORS 参数的值设置为高于 OPEN_CURSORS 参数的值,因为会话游标在打开状态下不会被缓存。

2.2 配置会话游标缓存

要启用会话游标缓存:

  1. 确定缓存中保留的会话游标的最大数量。
  2. 执行以下操作之一:
  • 要启用静态缓存,请将 SESSION_CACHED_CURSORS 参数的值设置为上一步中确定的数字。

  • 要启用动态缓存,请执行以下语句:

cpp 复制代码
ALTER SESSION SET SESSION_CACHED_CURSORS = value;

2.3 配置示例

1)设置打开游标参数

cpp 复制代码
ALTER SESSION SET SESSION_CACHED_CURSORS = 2000;

2)打开一定数量的游标

cpp 复制代码
declare
msql varchar2(2000);
mcur number;
mstat number;
begin
 for i in 1..1000 loop
     mcur := dbms_sql.open_cursor;
     msql := 'select object_id from t1 where object_id='||to_char(i);
     dbms_sql.parse(mcur,msql,dbms_sql.native);
     mstat :=dbms_sql.execute(mcur);
 end loop;
end;
/  

注意:测试环境使用,生产环境上不要执行此代码

3)查询打开游标的数量

cpp 复制代码
select count(1) from v$open_cursor;



  COUNT(1)

----------

     1000



SQL> 

三、调整会话游标缓存的大小

使用 V$SESSTAT 视图确定会话游标缓存的大小是否足以容纳数据库实例。

要调整会话游标缓存的大小:

  1. 查询 V$SESSTAT 视图以确定当前在特定会话中缓存了多少游标。
  2. 查询 V$SESSTAT 视图以查找在会话游标缓存中找到游标的解析调用的百分比。
  3. 如果满足以下条件,请考虑增加 SESSION_CACHED_CURSORS 参数的值:
  • 会话游标缓存计数接近最大值
  • 相对于总解析,会话游标缓存命中的百分比较低
  • 应用程序重复执行相同查询的解析调用

示例 3-1 查询 V$SESSTAT 视图

以下查询可查找特定会话中当前缓存的游标数量:

cpp 复制代码
set linesize 1000
col MAX_CACHED for a20
col USERNAME for a20

SELECT a.value curr_cached, p.value max_cached,
       s.username, s.sid, s.serial#
  FROM v$sesstat a, v$statname b, v$session s, v$parameter2 p
 WHERE a.statistic# = b.statistic#  and s.sid=a.sid and a.sid=&sid
   AND p.name='session_cached_cursors'
   AND b.name = 'session cursor cache count';

此查询的输出可能如下所示:

cpp 复制代码
CURR_CACHED MAX_CACHED USERNAME  SID    SERIAL#

----------- ---------- -------- ----- ----------

         49 50        APP         35       263

此输出显示当前为会话 35 缓存的游标数量接近最大值。

以下查询查找在会话游标缓存中找到游标的解析调用的百分比:

cpp 复制代码
SELECT cach.value cache_hits, prs.value all_parses,

       round((cach.value/prs.value)*100,2) as "% found in cache"

  FROM v$sesstat cach, v$sesstat prs, v$statname nm1, v$statname nm2

 WHERE cach.statistic# = nm1.statistic#

  AND nm1.name = 'session cursor cache hits'

  AND prs.statistic#=nm2.statistic#

  AND nm2.name= 'parse count (total)'

  AND cach.sid= &sid and prs.sid= cach.sid;

此查询的输出可能如下所示:

CACHE_HITS ALL_PARSES % found in cache

---------- ---------- ----------------

       34       700             4.57

此输出显示会话 35 的会话游标缓存中的命中数与解析总数相比较低。

在此示例中,将 SESSION_CACHED_CURSORS 参数的值设置为 100 可能有助于提高性能。

相关推荐
芭拉拉小魔仙20 分钟前
浏览器数据存储方法深度剖析:LocalStorage、IndexedDB、Cookies、OPFS 与 WASM - SQLite
数据库·sqlite·wasm
Mercury_@221 小时前
项目集成篇:springboot集成redistemple实现自定义缓存,并且可以设置过期时间
后端·缓存
老王笔记1 小时前
MySQL如何区分幻读和不可重复读
数据库·mysql
不爱学习的啊Biao1 小时前
【08】MySQL复杂查询:子查询语句详解与示例
数据库·mysql·子查询
st_331 小时前
Junit5 单元测试入门
数据库·单元测试·log4j
s***g5401 小时前
MySQL-操作数据库备份与恢复
数据库·mysql
CQU_JIAKE1 小时前
11.5【算法】6-1 表彰优秀学生(多态)
数据库
Elastic 中国社区官方博客2 小时前
使用数据层进行数据生命周期管理
大数据·数据库·elasticsearch·搜索引擎·全文检索·时序数据库
我爱李星璇3 小时前
Spring Boot项目的创建
java·数据库·spring boot
锵锵锵锵~蒋3 小时前
实时数据开发|Flink异步IO--提升性能和吞吐量
jvm·数据库·flink·实时数据开发