关于OPEN CURSORS和SESSION CACHED CURSORS


NOTES
=====
1. A cursor is an address on the client that points to the memory location of a SQL statement on the server. Multiple-client cursors may point at the same address on the server.
2. Remember that 'Client' and 'Server' sides may reside on the same machine - in which case Client/Server is a logical distinction.
3. If a cursor is open, then the statement will be in the sql_area, so no parsing is necessary. This is why locks may remain when a client is terminated abnormally (such as a PC Client being turned off without
closing open cursors).
4. SESSION_CACHED_CURSORS is the initialisation parameter that specifies how many cursors to hold open for a particular session.
5. HOLD_CURSOR is an precompiler parameter that specifies that an individual cursor should be held open. See Page 11-3 of the Programmer's guide to the Oracle Precompilers.
6. Both the soft and hard parse register as a parse in tkprof. Hashing the current statement updates the parse count.
7. Soft parse avoids many of the steps taken during the parse phase for a particular statement. Initial syntactic and semantic checks are made and then the statement is hashed and compared with hashed statements in the SQL area. If a match is found, then existing information is used and relatively expensive steps (such as query optimization etc.) are avoided.
8. The 10053 event is only invoked during a hard parse.
SQL语句的处理过程修正:
对照metalink给出的这个示意图,我们可以对SQL的处理过程作如下的描述:
1、检查是否有打开的游标,如果有,则直接通过游标link到位于PGA的private SQL AREA( private SQL area),转步骤11。否则,执行步骤2。
2、检查初始化参数SESSION_CACHED_CURSORS是否被设置,如果被设置,则同样可以通过游标指向到位于PGA的私有SQL AREA,转步骤11。否则执行步骤3。
3、检查HOLD_CURSOR以及RELEASE_CURSOR的设置。如果RELEASE_CURSOR=no(默认 no),HOLD_CURSOR=yes(默认为no),当ORACLE执行完SQL语句,为private SQL AREA分配的内存空间被保留,cursor和private SQL AREA之间的link也被保留,预编译程序不再使用它,同样可以通过这个指针直接在private SQL AREA获得语句,转步骤11。
这上面的三种情况,实际上都没有作任何parse,都是直接从位于PGA中的private SQL AREA获得语句并直接执行。此为fast parse。
这三种情况都不存在的情况下,oracle转到步骤4执行。
4、创建一个游标。
5、语法检查Syntax Check:检查语法书写是否正确,是否符合SQL Reference Manual中给出的SQL语法。
6、语义分析Semantic Analysis:查找数据字典,检查表、列是否正确,在所要求的对象上获取语法分析锁,使得在语句的语法分析过程中不改变这些对象的定义, 验证为存取所涉及的模式对象所需的权限是否满足。
7、将语句转化成ASCII等效数字码,再通过散列算法得到散列值。
8、检查库缓存中是否存在同样hash值的语句。如果存在,转步骤11。否则,执行步骤9。 这就是soft parse。
9、选择执行计划。从可用的执行计划中选择一个最优的执行计划,其中包括存储大纲(srored outline)或物化视图(materialized view)相关的决定。
10、生成该语句的一个编译代码(p-code)。
11、执行语句。
cursor:from Oracle9i Database Concepts:A cursor is a handle or name for a private SQL area--an area in memory in which a parsed statement and other information for processing the statement are kept.
当某个session执行一条语句之后,该语句的parse结果会在library cache中保存,同时也会在PGA的private sql area有一个拷贝的副本。cursor 总是通过一个link是直接链到 private sql area的。如果在private中没有找到这个副本,就需要对SQL进行parse,然后再在library cache中进行hash值的匹配。所以总的来说,使用cursor能不需要任何parse,就是因为直接从当前的private sql area中得到了语句相关信息,包括执行计划。而一旦需要到library cache中进行匹配,就必须需要parse。soft parse不是不作parse,只是parse的量比较小,只需要作语法检查和语义分析,以及散列语句。
关于预编译的两个参数说明:
HOLD_CURSOR:HOLD_CURSOR默认值为no,当oracle执行完sql语句,close游标之后,预编译程序将游标和缓存SQL的 cache链接标记为可重 用。并且释放已经分配给该语句的私有SQL AREA内存区域,解除parse locks。当有下一个语句需要使用时,这个链接立即被重用。当HOLD_CURSOR=YES时,当oracle执行完sql语句,为private SQL AREA分配的内存空间被保留,cursor和private SQL AREA之间的link也被保留,预编译程序不再使用它。
RELEASE_CURSOR:RELEASE_CURSOR的优先级高于HOLD_CURSOR。RELEASE_CURSOR默认值为no。 RELEASE_CURSOR=yes,当oracle执行完sql语句,close游标之后,缓存被释放,锁被解除,链接被标识为可重用。RELEASE_CURSOR=no,则主要有 HOLD_CURSOR来决定了。
另外说明一点,这两个参数是在预编译的文件中定义的。
这部分内容详细见:oracle documents -> Programmer's Guide to the Oracle Precompilers -> Performance Tuning ->   Optimizing SQL Statements   -> Using the Cursor Management Options
标签: 暂无标签
oraunix

写了 199 篇文章,拥有财富 1026,被 339 人关注

转播转播 分享分享 分享淘帖
回复

使用道具

P4 | 发表于 2012-9-29 10:38:40
下面是我们一个生产环境的情况,最大使用的open_cursor数和open_cursor参数预设值相差很大,如果机子负载大的话能不能把open_cursor再设小一点?使用数和参数值保持多大的比例比较好?
SQL> SELECT MAX(A.VALUE) AS HIGHEST_OPEN_CUR, P.VALUE AS MAX_OPEN_CUR  
  2  FROM V$SESSTAT A, V$STATNAME B, V$PARAMETER P  
  3  WHERE A.STATISTIC# = B.STATISTIC#  
  4  AND B.NAME = 'opened cursors current'  
  5  AND P.NAME = 'open_cursors'  
  6  GROUP BY P.VALUE;

HIGHEST_OPEN_CUR
----------------
MAX_OPEN_CUR
--------------------------------------------------------------------------------
              60
800                        
回复

使用道具

P6 | 发表于 2010-12-8 11:11:53
我以前上课讲过,就是使用OCI、JDBC等,可以控制实现无解析,其实就是控制私有SQL的释放。
回复

使用道具

P4 | 发表于 2010-12-6 14:58:31
上面的代码是PRO*C的代码,不是PL/SQL。
在用PRO*C时,可用HOLD_CURSOR、RELEASE_CURSOR以及MAX_OPENCURSOR参数来控制专用SQL区。在使用OCI时,可使用OSQL3或OPARSE调用来为SQL语句分配专用SQL区,用OCLOSE调用关闭光标和释放专用SQL区。在使用SQL *Forms时,同样也可控制是否重用专用SQL区:可在触发器级、Form级或在运行时减少语法分析调用,以减少或重用专用SQL区;
所以HOLD_CURSOR 和 RELEASE_CURSOR 是在PRO*C的开发时设置的内部参数。
回复

使用道具

P4 | 发表于 2010-12-5 10:50:32
本帖最后由 chenyu 于 2010-12-5 11:23 编辑

2、检查初始化参数SESSION_CACHED_CURSORS是否被设置,如果被设置,则同样可以通过游标指向到位于PGA的私有SQL AREA,转步骤11。否则执行步骤3。
如果这个SQL从来没有执行过,哪么即使设置了SESSION_CACHED_CURSORS,也需要执行一次hard parse吧,我觉得“始化参数SESSION_CACHED_CURSORS是否被设置”这句话改为“如果在SESSION_CACHED_CURSORS中找到游标信息(找到表明肯定设置了这个初始话参数)”更加合适,SQL语句在执行三次以后才会在SESSION_CACHED_CURSORS中记录游标信息;

3、检查HOLD_CURSOR以及RELEASE_CURSOR的设置。如果RELEASE_CURSOR=no(默认 no),HOLD_CURSOR=yes(默认为no),当ORACLE执行完SQL语句,为private SQL AREA分配的内存空间被保留,cursor和private SQL AREA之间的link也被保留,预编译程序不再使用它,同样可以通过这个指针直接在private SQL AREA获得语句,转步骤11。
这上面的三种情况,实际上都没有作任何parse,都是直接从位于PGA中的private SQL AREA获得语句并直接执行。此为fast parse

同上,我觉得和上面不同之处在于设置完这两个参数后只需要执行一次SQL语句(一次hard parse)就能够缓存游标和private sql area等信息;

另外oracle docement上面关于ORACA的试验代码是在那里运行的?直接在SQLPLUS中运行报错;代码如下:
EXEC SQL BEGIN DECLARE SECTION;
username CHARACTER(20);
password CHARACTER(20);
emp_name INTEGER;
dept_number INTEGER;
salary REAL;
EXEC SQL END DECLARE SECTION;
EXEC SQL INCLUDE SQLCA;
EXEC SQL INCLUDE ORACA;
display 'Username? ';
read username;
display 'Password? ';
read password;
EXEC SQL WHENEVER SQLERROR DO sql_error;
EXEC SQL CONNECT :username IDENTIFIED BY :password;
display 'Connected to Oracle';
EXEC ORACLE OPTION (ORACA=YES);
-- set flags in the ORACA
set oraca.oradbgf = 1; -- enable debug operations
set oraca.oracchf = 1; -- enable cursor cache consistency check
set oraca.orastxtf = 3; -- always save the SQL statement
display 'Department number? ';
read dept_number;
EXEC SQL DECLARE emp_cursor CURSOR FOR
SELECT ENAME, SAL + NVL(COMM,0)
FROM EMP
WHERE DEPTNO = :dept_number;
EXEC SQL OPEN emp_cursor;
EXEC SQL WHENEVER NOT FOUND DO no_more;
rLOOP
EXEC SQL FETCH emp_cursor INTO :emp_name, :salary;
IF salary < 2500 THEN
EXEC SQL INSERT INTO PAY1 VALUES (:emp_name, :salary);
ELSE
EXEC SQL INSERT INTO PAY2 VALUES (:emp_name, :salary);
ENDIF;
ENDLOOP;
ROUTINE no_more
BEGIN
EXEC SQL CLOSE emp_cursor;
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL COMMIT WORK RELEASE;
display 'Last SQL statement: ', oraca.orastxt.orastxtc;
display '... at or near line number: ', oraca.oraslnr;
display
display ' Cursor Cache Statistics';
display '-------------------------------------------';
display 'Maximum value of MAXOPENCURSORS ', oraca.orahoc;
display 'Maximum open cursors required: ', oraca.oramoc;
display 'Current number of open cursors: ', oraca.oracoc;
display 'Number of cache reassignments: ', oraca.oranor;
display 'Number of SQL statement parses: ', oraca.oranpr;
display 'Number of SQL statement executions: ', oraca.oranex;
exit program;
END no_more;
ROUTINE sql_error
BEGIN
EXEC SQL WHENEVER SQLERROR CONTINUE;
EXEC SQL ROLLBACK WORK RELEASE;
display 'Last SQL statement: ', oraca.orastxt.orastxtc;
display '... at or near line number: ', oraca.oraslnr;
display
display ' Cursor Cache Statistics';
display '-------------------------------------------';
display 'Maximum value of MAXOPENCURSORS ', oraca.orahoc;
display 'Maximum open cursors required: ', oraca.oramoc;
display 'Current number of open cursors: ', oraca.oracoc;
display 'Number of cache reassignments: ', oraca.oranor;
display 'Number of SQL statement parses: ', oraca.oranpr;
display 'Number of SQL statement executions: ', oraca.oranex;
exit program with an error;
END sql_error;
回复

使用道具

您需要登录后才可以回帖 登录 | 加入社区

本版积分规则

意见
反馈