深入解析Cursor和绑定变量

719,我在Oracle举办的“Oracle 技术网开发人员日”活动上,我就“深入解析Cursor和绑定变量”这个主题做了一点分享,重点是放在说明Oracle里的Cursor到底是什么以及介绍一下已经在我们项目成功实施过的开发经验。

 

如下是我就这次演讲的内容做的一点概括,里面也包含了我回答一些朋友的问题的邮件内容:

Oracle里的cursor分为两种:一种是shared cursor,一种是session cursor

 

所谓的shared cursor就是指缓存在library cache里的一种library cache object,说白了就是指缓存在library cache里的sql和匿名pl/sql。它们是Oracle缓存在library cache中的几十种library cache object之一,它所属于的namespaceCRSR(也就是cursor的缩写)。你信里提到的parent cursorchild cursor都是shared cursor,它们都是以library cache object handle的方式存在library cache里,当一条sql第一次被执行的时候,会同时产生parent cursorchild cursorparent cursorlibrary cache object handleheap 0里会存储其child cursor的地址,这个sql的执行计划会存储在上述child cursorlibrary cache object handleheap 6中,第一次执行上述sql所产生的parent cursorchild cursor的过程也就是所谓的硬解析主要做的事情。如果上述sql再次执行,Oracle只需要去扫描相应的library cache object handle,找到上次硬解析后产生的child cursor,把里面的parse tree和执行计划直接拿过用就可以了,这就是所谓的软解析

 

Oracle里的第二种cursor就是session cursorsession cursor又分为三种:分别是implicit cursorexplicit cursorref cursor。所谓的session cursor其实就是指的跟这个session相对应的server processPGA里(准确的说是UGA)的一块内存区域(或者说内存结构),它的目的是为了处理且一次只处理一条sql语句(这里是指一个implicit cursor一次只处理一条sqlexplicit cursorref cursor处理sql的数量是由你自己所控制

 

一个session cursor只能对应一个shared cursor,而一个shared cursor却可能同时对应多个session cursor

 

session_cached_cursors的值大于0的时候,当一个session cursor处理完一条sql后,它就不会被destroyOracle会把其cache起来(我们称之为soft closed session cursor),这么做的目的是很明显的,当在这个session中再次执行同样的sql的时候,Oracle就不再需要reopen这个cursor了(即省掉了重新openclose这个cursor的时间),直接把刚才已经soft closed掉的session cursor拿过来用就好了,这就是所谓的“软软解析”

最后我说一下特别容易混淆的Oracle里几个关于cursor的参数的含义:

 

1open_cursors

open_cursors指的是在单个session中同时能以open状态存在的session cursor的最大数量 

 

2session_cached_cursors

session_cached_cursors指的是单个session中同时能cache住的soft closed session cursor的最大数量

 

3cursor_space_for_time

关于cursor_space_for_time有三点需要注意:1) 10.2.0.511.1.0.7里它已经作废了;2) 把它的值调成true后如果还同时用到了绑定变量,则由于Bug 6696453的关系,可能会导致logical data corruption3) 把它的值调成true后,所有的child cursor在执行完后依然会持有library cache pin,直到其parent cursor关闭

 

首先我们来看一下library cache object所属于的namespace的定义:

1. Library cache objects are grouped in namespaces according to their type.

2. Each object can only be of one type.

3. All the objects of the same type are in the same namespace.

4. A namespace may be used by more than one type.

5. The most important namespace is called cursor (CRSR) and houses the shared SQL cursors.

 

你在obj$看到的关于namespace的解释当然是不全的,因为像shared cursor这样的library cache object根本就不在obj$里。

 

所以实际上你可以这样理解:namespace是针对缓存在library cache里的library cache object来说的,那为什么obj$里会有namespace的定义呢?——因为library cache object有一部分的来源就是来自于数据库里已经存在的、固化的objectmetadata

 

我们再来看一下library cache object所属于的namespace的详细说明:

Currently there are 64 different object types but this number may grow at any time with the introduction of new features. Examples of types are: cursor, table, synonym, sequence, index, LOB, Java source, outline, dimension, and so on. Not every type corresponds to a namespace. Actually, there are only 32 namespaces which, of course, are also subject to increase at any time.

What is a certainty is that all the objects of the same type will always be stored in the same namespace. An object can only be of one type, hence the search for an object in the library cache is reduced to a search for this object in the corresponding namespace.

Some namespaces contain objects of two or three different types. These are some of the most commonly used namespaces:

CRSR: Stores library objects of type cursor (shared SQL statements)

TABL/PRCD/TYPE: Stores tables, views, sequences, synonyms, procedure specifications, function specifications, package specifications, libraries, and type specifications

BODY/TYBD: Stores procedure, function, package, and type bodies

TRGR: Stores library objects of type trigger

INDX: Stores library objects of type index

CLST: Stores library objects of type cluster

The exact number and name of namespaces in use depends on the server features that are used by the application. For example, if the application uses Java, namespaces like JVSC (Java source) and JVRE (Java resource) may be used, otherwise they will not be used.

Note: These namespaces do not store tables, clusters, or indexes as such, only the metadata is stored.

 

最后的结论是:我也看不到KQD.H的内容,所以我也无法知道Oracle里所有的namespace的准确namespace id,但是其实你是可以通过library cache dump里的所有namespace的列表来猜出来的,因为这显示是按namespace id来排序的。

可以通过library cache dump知道某个Oracle的版本下所有的namespace,如下所示的是9.2.0.6的:

LIBRARY CACHE STATISTICS:
namespace           gets hit ratio      pins hit ratio    reloads   invalids
————– ——— ——— ——— ——— ———- ———-
CRSR                1078     0.860      4989     0.935         17          0
TABL/PRCD/TYPE       596     0.636       780     0.624          0          0
BODY/TYBD              1     0.000         0     0.000          0          0
TRGR                   1     0.000         1     0.000          0          0
INDX                  76     0.474        45     0.111          0          0
CLST                 148     0.953       203     0.961          0          0
OBJE                   0     0.000         0     0.000          0          0
PIPE                   0     0.000         0     0.000          0          0
LOB                    0     0.000         0     0.000          0          0
DIR                    0     0.000         0     0.000          0          0
QUEU                  30     0.700        30     0.700          0          0
OBJG                   0     0.000         0     0.000          0          0
PROP                   0     0.000         0     0.000          0          0
JVSC                   0     0.000         0     0.000          0          0
JVRE                   0     0.000         0     0.000          0          0
ROBJ                   0     0.000         0     0.000          0          0
REIP                   0     0.000         0     0.000          0          0
CPOB                   0     0.000         0     0.000          0          0
EVNT                   1     0.000         1     0.000          0          0
SUMM                   0     0.000         0     0.000          0          0
DIMN                   0     0.000         0     0.000          0          0
CTX                    0     0.000         0     0.000          0          0
OUTL                   0     0.000         0     0.000          0          0
RULS                   0     0.000         0     0.000          0          0
RMGR                   0     0.000         0     0.000          0          0
IFSD                   1     0.000         0     0.000          0          0
PPLN                   0     0.000         0     0.000          0          0
PCLS                   0     0.000         0     0.000          0          0
SUBS                   0     0.000         0     0.000          0          0
LOCS                   0     0.000         0     0.000          0          0
RMOB                   0     0.000         0     0.000          0          0
RSMD                   0     0.000         0     0.000          0          0
JVSD                   0     0.000         0     0.000          0          0
ENPR                   0     0.000         0     0.000          0          0
RELC                   0     0.000         0     0.000          0          0
STREAM                 0     0.000         0     0.000          0          0
APPLY                  0     0.000         0     0.000          0          0
APPLY SOURCE           0     0.000         0     0.000          0          0
APPLY DESTN            0     0.000         0     0.000          0          0
TEST                   0     0.000         0     0.000          0          0
CUMULATIVE          1932     0.778      6049     0.888         17          0

 

从结果里看9.2.0.6是一共有40namespace


5 Comments on “深入解析Cursor和绑定变量”

  1. wxjzqymtl says:

    学习了 最近正在学习shared pool内存结构,看了之后受益匪浅 谢谢分享

  2. wxjzqymtl says:

    博主你好,这次再次学习您这篇帖子有如下两个问题求教
    1.oracle concept中关于cursor提到了普通cursor(与私有sql区有关),
    recursive cursor(与共享sql区有关),scrollable cursor(与查询结果集有关);
    而plsql user guide里提到的cursor也是和私有sql区有关且可以分为implicit,explicit,ref cursor;
    再结合博主说的shared cursor和session cursor,有了我以下很是迷糊的理解:
    这里看上去关系最近的就是concept中提及的普通cursor和plsql user guide中提及的cursor,
    原因是他们都和私有sql区有关;而plsql user guide中提及的cursor按分类来讲就是博主说的session
    cursor;越说越糊涂,希望博主对这几种cursor的关系给我说说,在此非常感谢
    2.关于提到session_cached_cursor大于0时会实现session cursor的软关闭,
    我所了解的关于cache cursor是通过隐含参数_close_cached_open_cursors实现的,默认值为false,
    那在默认情况对于重复执行的sql就已经开启了软关闭的特性。于是我做了如下操作来观察这两个
    参数对cursor软关闭的影响:分别在(session_cached_cursor=0和隐含参数为false),
    (session_cached_cursor>0和隐含参数为true),(session_cached_cursor=0和隐含参数为true)三种
    情况下对同一条sql执行100000次,通过v$librarycache中sql area命名空间中的gets指标观察该值
    只增加了几百,那么从这里可以看出session cursor的软关闭是一直存在的了,和博主说的参数和我
    说的参数没有关系.是我的测试方法或是理解哪里出问题了希望博主给点建议

    • cui hua says:

      1、Oracle里的cursor不是三言两语就能说清楚,事实上我在部门内做培训的时候这一块儿的内容我讲了10个小时;
      2、你自己去查一下你提到的那个隐含参数的含义吧;
      3、你可以用select * from v$sesstat where statistic# in (select statistic# from v$statname where name like ‘%session cursor cache count%’)来观察你想观察的内容

  3. wxjzqymtl says:

    忘记说明一点我的测试环境为redhat 5.5(32bit)
    oracle 10.2.0.1

  4. wxjzqymtl says:

    感谢博主的回复,有时间的话麻烦上面的问题也回复下 哈哈


Leave a Reply

Your email address will not be published. Required fields are marked *