基于Oracle的SQL优化--学习(九)
Oracle里的Cursor和绑定变量
Oracle里的Cursor
Oracle数据库中的Cursor分为两种类型:一种是Shared Cursor;另一种是Session Cursor。
Oracle里的Shared Cursor
oracle 数据库中的 Shared Cursor 就是指缓存在库缓存里的一种库缓存对象,说白了就是指缓存在库缓存堆的 sQL 语句和匿名 PIJSQL 语句所对应的库缓存对象。 Shared Cursor是 oracle 缓存在 Library Cache中的几十种库缓存对象之一,它所对应的库缓存对象句柄的 Namespace 属性的值是 CRSR (也就是Cursor 的缩写)。shared Cursor 里会存储目标 SQL 的 SQL 文本、解析树、该 SQL 所涉及的对象定义、该 sQL 所使用的绑定变量类型和长度.以及该 SQL 的执行计划等信息。
Oracle数据库中的 Shared Cursor 又细分为 Parent Cursor (父游标)和 Child Cursor (子游标)这两种类型,我们可以通过分别查询视图 V $ SOLAREA 和V $ SOL 来查看当前缓存在库级存中的 parent Cursor 和 Child Cursor ,其中 V $ SQLAREA 用于变看 Parent Cursor ,V $ SOL用于变看 Child Cursor 。
Parent Cursor 和 Child Cursor的结构是 ·一样的(它们都是以库缓存对象句柄的方式缓存在库缓存中, Namespace 属性的值均为 CRsR ) .它们的区别在于目标 sQL 的 sQL 文本会存储在其Parent Cursor 所对应的库缓存对象句柄的属性 Name中( Child Cursor 对应的库缓存对象句柄的 Name 属性值为空,这意味着只有通过 Parent Cursor 才能找到相应的 Child cursor ) ,而该 SQL 的解析树和执行计划则会存储在其 Child Cursor所对应的库缓存对象句柄的 Heap 6 中。同时Oracle会在该 sQL 所对应的 Parent Cursor的 Heap 0 的 child table 中.存储从属于该 Parent Cursor的所有 Child Cursor,的库级存对象句柄地址(这意味着 Oracle可以通过访问 Parent Cursor的 Heap 6的 child table而依次顺序访问从属于该 Parent Cursor 的所有 Child Cursor ) .
这种Parent Cursor 和 Child Cursor的结构就决定了在 Oracle数据库里,任何一个目标 SQL 一定会同时对应两个Shared Cursor ,其中一个是 Parent Cursor.另外一个则是 Child Cursor. Parent Cursor会存储该SQL的 SQL 文本.而该 SQL 其正的可以被重用的解析树和执行计划则存储在 child Cursor 中。
硬解析
硬解析( Hard Parse )是指 Oracle 在执行目标 SQL 时.在库缓存中找不到可以重用的解析树和执行计划,而不得不从头开始解析目标 SQL 并生成相应的 Parent Cursor 和 Child Cursor的过程。硬解析实际上有两种类型: ·一种是在库缓存中找不到匹配的 Parent Cursor ,此时 oradc 会从头开始解析目标 SQL ,新生成一个Parent Cursor 和 Child Cursor,并把它们挂在对应的 Hash Bucket 中:另外 一种是找到了匹配的 Parent Cursor未找到匹配的 child Cursor .此时 oracle 也会从头开始解析该日标 SQL .新生成一个 Child Cursor。并把这个 Child Cursor 挂在对应的 Parent Cursor下。
硬解析很不好,有以下缺点:
(1)硬解析可能会导致Shared Pool Latch的争用。
(2)硬解析可能会导致库缓存相关Latch(如Library Cache Latch)和Mutex的争用。
软解析
软解析是指Oracle在执行目标SQL时,在Library Cache中找到匹配的Parent Cursor 和 Child Cursor,并将存储在Child Cursor中的解析树和执行计划直接拿过来重用而无须从头开始解析的过程。
与硬解析相比,软解析优势是:
(1)软解析不会导致Shared Pool Latch的争用。
(2)软解析虽然也可能会导致库缓存相关 Latch 和 Mutex 的争用.但软解析持有库级存相关 Latch 的次数要少,而且软解析对某些 Latch (如 Library Cache Latch )的持有时间会比硬解析短,这意味,即使产生了库级存相关 Latch 的争用,软解析的争用程度也没有硬解析那么严重即库级存相关 Lalch 和 Mutex 的争用所带来的系统性能和可扩展性的问从对软解析来说要比硬解析少很多。
Oracle里的Session Cursor
Session Cursor的含义
Oracle数据库里第二种类型的 Cursor 就是Session Cursor,它是当前Session 解析和执行 SQL 的载体.换句话说, Session Cursor 用于在当前 Session 中解析和执行 SQL .和 Shared Cursor 一样, Session Cursor也是 oracle 自定义的 一种 C 语言复杂结构,它也是以哈希表的方式缓存起来的,只不过是缓存在 PGA 中,而不是像 Shared Cursor那样缓存在 SGA的库缓存里。
关于Session Cursor,有以下需要注意:
( 1 )Session Cursor 与 session 是一一对应的,不同 session 的 session Cursor 之间没法共享,这与 Shared Cursor有本质区别.
( 2 ) Session Cursor是有生命周期的,每个Session Cursor 在使用的过程中都至少会经历一次Open、Parse、 Bind 、 Execute 、 Fdch 和 Close中的一个或多个阶段,用过的 Session Cursor不 一定会缓存在对应义Session 的PGA中,这取决于参数SESSION_CACHED_CURSORS的值是否大于 0
( 3 )既然 scssion Cursor 也是以哈希表的方式缓存在 PGA 中,意味着 Oracle会通过相关的哈希运算来存储和访问在当前 Session 的 PGA 中的对应 Session Cursor .这种访问机制实际上和Shared Cursor是一样的,即可以简单地认为Oracle是根据目标 SQL 的 SQL 文本的哈希值去PAG中的相应 Hash Bucket 中找匹配的 Session Cursor。
Oracle在解析和执行目标SQL时,会先去当前Session的PGA中找是否存在匹配的缓存Session Cursor。当Oracle第一次解析和执行目标SQL时,当前Session的PGA中肯定不存在匹配的Session Cursor,这时Oracle会新生成一个Session Cursor和一对Shared Cursor,这其中的Shared Cursor会存储能被所有Session共享、重用的内容。而Session Cursor则会经历一次Open、Parse、 Bind 、 Execute 、 Fdch 和 Close中的一个或多个阶段。
Session Cursor的相关参数解析
OPEN_CURSORS
参数 OPEN_CURSORS用于设定单个Session中同时能够以 Open状态并存的Session Cursor 的总数。 SESSION_CACHED_CURSORS
参数SESSION_CACHED_CURSORS用于设定单个Session中鞥能够以Soft Closed状态并存的Session Cursor 的总数。即用于设定单个Session能缓存在PGA中的Session Cursor 的总数。
CURSOR_SOACE_FOR_TIME
参数CURSOR_SOACE_FOR_TIME是为了环节发生在Child Cursor上的与库缓存相关的Latch争用。
Session Cursor的种类和用法
隐式游标
隐式游标是 Oracle数据库中最常见的一种 Session Cursor.它无处不在,我们在 SQLPLUs 或者在 PL/SQL 代码中直接执行 sQL 语句时, Oracle 实际上都帮我们自动创建了隐式游标来作为这些SQL 语句执行的载体.之所以称为隐式游标,是因为它的生命周期管理全部是由 SQL引擎或 PUSQL 引擎自动来完成,所以我们常常感觉不到它的存在。
隐式游标的属性
1、SQL%FOUND属性
SQL%FOUND表示一条 sQL 语句被执行成功后受其影响而改变的记录数是否大于或等于 l 。既然是要改变记录,这意味着 SQL % FOUND 通常适用于那终执行 INSET、 UPDATE 和 DELETE 操作的 OML 语句,当然,它其实也可以用于 SELECT 语句.在一条 DML 语句被执行前,SQL%FOUND的值是 NULL .当这条 DML 语句被执行并且成功改变了一条或者一条以卜记录的时候,又或者 SELECT语句成功返回一条或者条以上记录的时候,SQL%FOUND的值是 TRUE ,否则为 FALSE 。
2、SQL%NOTFOUND
SQL%FOUND表示一条SQL被执行成功后受其影响而改变的记录数是否为0。
3、SQL%ISOPEN
SQL%ISOPEN表示隐式游标是否处于Open状态。
4、SQL%ROWCOUNT
SQL%ROWCOUNT表示一条SQL语句成功执行后受其影响而改变的记录数的数量。
显式游标
显式游标通常用于PL/SQL代码中,它的定义和生命周期管理中的Open、 Fdch 和 Close均有我们在PL/SQL代码中显式控制。
显式游标的属性:
1、CURSORNAME%FOUND
CURSORNAME%FOUND属性拜师指定的显式游标是否至少有一条记录被Fdch了。
2、CURSORNAME%ISOPEN
CURSORNAME%ISOPEN表示指定的显式游标是否被Open。
3、CURSORNAME%NOTFOUND
CURSORNAME%NOTFOUND表示指定的显示游标是否已经Fetch完毕。
4、CURSORNAME%ROWCOUNT
CURSORNAME%ROWCOUNT表示指定的显示游标迄今为止一共Fetch了多少行记录。
参考游标
参考游标通常用于PL/SQL代码中,它的定义和生命周期管理中的Open、 Fdch 和 Close均有我们在PL/SQL代码中显式控制。
参考游标的属性和显示游标是一样的。其是Session Cursor中最灵活的,其灵活性体现在:
1、它可以有多种定义方式。
2、参考游标的 Open方式也非常灵活,它可以不和某个固定的 SQL 绑定,参考游标可以随时open ,并且每次Open所对应的 sQL 语句部可以是不一样的
3、参考游标可以作为存储过程的输入参数和函数的输出参数。