关于Buffer Cache,oracle提供一些重要视图,用于查询关于Buffer Cache的重要信息,为调整Buffer Cache、提高性能提供参考。下面一一介绍它们
上面我们提到了Oracle的建议器,其中有一个针对Buffer Cache的建议器。在我们设置了参数db_cache_advice为TRUE后,经过一段时间的系统运行,Oracle收集到相关统计数据,并根据一定的数学模型,预测出DB_CACHE_SIZE在不同大小情况的性能数据。我们就可以由视图V$DB_CACHE_ADVICE查出这些数据,并根据这些数据调整DB_CACHE_SZIE,使系统性能最优。
下面是关于这个视图的结构描述:
字段 |
数据类型 |
描述 |
ID |
NUMBER |
缓冲池标识号(从1到8,1-6对应于DB_nK_CACHE_SIZE,DB_CACHE_SIZE与系统标准块尺寸的序号相关,如DB_BLOCK_SIZE为8K,则DB_CACHE_SIZE的标识号为3(2,4,8…)。7是DB_KEEP_CACHE_SIZE,8是DB_RECYCLE_CACHE_SIZE) |
NAME |
VARCHAR2(20) |
缓冲池名称 |
BLOCK_SIZE |
NUMBER |
缓冲池块尺寸(字节为单位) |
ADVICE_STATUS |
VARCHAR2(3) |
建议器状态:ON表示建议器在运行;OFF表示建议器已经关闭。当建议器关闭了,视图中的数据是上一次打开所统计得出的。 |
SIZE_FOR_ESTIMATE |
NUMBER |
预测性能数据的Cache大小(M为单位) |
SIZE_FACTOR |
NUMBER |
预测的Cache大小因子(即与当前大小的比例) |
BUFFERS_FOR_ESTIMATE |
NUMBER |
预测性能数据的Cache大小(缓冲块数) |
ESTD_PHYSICAL_READ_FACTOR |
NUMBER |
这一缓冲大小时,物理读因子,它是如果缓冲大小为SIZE_FOR_ESTIMATE时,建议器预测物理读数与当前实际物理读数的比率值。如果当前物理读数为0,这个值为空。 |
ESTD_PHYSICAL_READS |
NUMBER |
如果缓冲大小为SIZE_FOR_ESTIMATE时,建议器预测物理读数。 |
下面是从这个视图中查询出来的数据:
SQL> select size_for_estimate, estd_physical_read_factor, estd_physical_reads
2 from v$db_cache_advice
3 where name = 'DEFAULT';
SIZE_FOR_ESTIMATE ESTD_PHYSICAL_READ_FACTOR ESTD_PHYSICAL_READS
----------------- ------------------------- -------------------
16 2.0176 6514226
32 1.7403 5619048
48 1.5232 4917909
64 1.3528 4367839
80 1.2698 4099816
96 1.1933 3852847
112 1.1443 3694709
128 1.1007 3553685
144 1.0694 3452805
160 1.0416 3362964
176 1.0175 3285085
192 1 3228693
208 0.9802 3164754
224 0.9632 3109920
240 0.9395 3033427
256 0.8383 2706631
272 0.7363 2377209
288 0.682 2202116
304 0.6714 2167888
320 0.6516 2103876
20 rows selected
当前我们的DB_CACHE_SIZE为192M,可以看到,它的物理读因子为1,物理读数为3228693。那么如何根据这些数据调整DB_CACHE_SIZE呢?给出一个方法,找到变化率较平缓的点作为采用值。因为建议器做预测是,DB_CACHE_SIZE的预测值的增长步长是相同的,是16M。我们按照这一步长增加DB_CACHE_SIZE,如果每次增加物理读降低都很明显,就可以继续增加,直到物理读降低不明显,说明继续增加DB_CACHE_SIZE没有太大作用。当然,性能和可用资源是天平的两端,你需要根据自己系统的实际情况调整。
上面的例子中,我们可以考虑将DB_CACHE_SIZE调整到288M。因为在288M之前,物理读因子变化都比较大,而从288M到304M以后,这个因子变化趋缓。用一个二维图可以更容易看出这个变化来:
这一视图作为调整DB_CACHE_SIZE以提高性能有很大参考价值。但衡量Buffer Cache是否合适的重要指标还是我们前面提到的缓存命中率(Buffer Hit),而影响缓存命中率往往还有其他因素,如性能极差的SQL语句。
这一视图显示了当前实例中所有缓冲池的信息。它的结构如下:
字段 |
数据类型 |
描述 |
ID |
NUMBER |
缓冲池ID,和上面视图描述相同。 |
NAME |
VARCHAR2(20) |
缓冲池名称 |
BLOCK_SIZE |
NUMBER |
缓冲池块尺寸(字节为单位) |
RESIZE_STATE |
VARCHAR2(10) |
缓冲池当前状态。 STATIC:没有被正在调整大小 ALLOCATING:正在分配内存给缓冲池(不能被用户取消) ACTIVATING:正在创建新的缓存块(不能被用户取消) SHRINKING:正在删除缓存块(能被用户取消) |
CURRENT_SIZE |
NUMBER |
缓冲池大小(M为单位) |
BUFFERS |
NUMBER |
当前缓存块数 |
TARGET_SIZE |
NUMBER |
如果正在调整缓冲池大小(即状态不为STATIC),这记录了调整后的大小(M为单位)。如果状态为STATIC,这个值和当前大小值相同。 |
TARGET_BUFFERS |
NUMBER |
如果正在调整缓冲池大小(即状态不为STATIC),这记录了调整后的缓存块数。否则,这个值和当前缓存块数相同。 |
PREV_SIZE |
NUMBER |
前一次调整的缓冲池大小。如果从来没有调整过,则为0。 |
PREV_BUFFERS |
NUMBER |
前一次调整的缓存块数。如果从来没有调整过,则为0。 |
LO_BNUM |
NUMBER |
9i后已经废弃字段 |
HI_BNUM |
NUMBER |
9i后已经废弃字段 |
LO_SETID |
NUMBER |
9i后已经废弃字段 |
HI_SETID |
NUMBER |
9i后已经废弃字段 |
SET_COUNT |
NUMBER |
9i后已经废弃字段 |
V$BUFFER_POOL_STATISTICS视图记录了所有缓冲池的统计数据。它的结构如下:
字段 |
数据类型 |
描述 |
ID |
NUMBER |
缓冲池ID,和上面视图描述相同。 |
NAME |
VARCHAR2(20) |
缓冲池名称 |
SET_MSIZE |
NUMBER |
缓冲池中缓存块的最大数 |
CNUM_REPL |
NUMBER |
在置换列表中的缓存块数 |
CNUM_WRITE |
NUMBER |
在写列表中的缓存块数 |
CNUM_SET |
NUMBER |
当前的缓存块数 |
BUF_GOT |
NUMBER |
读取过的缓存块数 |
SUM_WRITE |
NUMBER |
被写过的缓存块数 |
SUM_SCAN |
NUMBER |
被扫描过的缓存块数 |
FREE_BUFFER_WAIT |
NUMBER |
等待空闲块统计数 |
WRITE_COMPLETE_WAIT |
NUMBER |
等待完成写统计数 |
BUFFER_BUSY_WAIT |
NUMBER |
忙(正在被使用)等待统计数 |
FREE_BUFFER_INSPECTED |
NUMBER |
确认了的空闲缓存块数(即可用的) |
DIRTY_BUFFERS_INSPECTED |
NUMBER |
确认了的脏缓存块数 |
DB_BLOCK_CHANGE |
NUMBER |
被修改过的数据块数 |
DB_BLOCK_GETS |
NUMBER |
读取过的数据块数 |
CONSISTENT_GETS |
NUMBER |
一致性读统计数 |
PHYSICAL_READS |
NUMBER |
物理读统计数 |
PHYSICAL_WRITES |
NUMBER |
物理写统计数 |
查看当前的Buffer Cache命中率:
SQL> select 1-(physical_reads)/(consistent_gets+db_block_gets)
2 from v$buffer_pool_statistics;
1-(PHYSICAL_READS)/(CONSISTENT
------------------------------
0.967658520581074
SQL>
这一视图在深入定位缓冲区问题时很有用。它记录了缓冲区中所有数据块对象。粒度非常细。这个视图最初的目的是用于OPS(Oracle Parallel Server Oracle平行服务器,9i后称为RAC)的,是用于保证RAC中各个节点的数据一致性的。但是,我们可以通过它来查询Buffer Cache的使用情况,找出大量消耗Buffer Cache的对象。下面的语句就可以完成这一工作:
SQL> column c0 heading 'Owner' format a15
SQL> column c1 heading 'Object|Name' format a30
SQL> column c2 heading 'Number|of|Buffers' format 999,999
SQL> column c3 heading 'Percentage|ofData|Buffer' format 999,999,999
SQL> select
2 owner c0,
3 object_name c1,
4 count(1) c2,
5 (count(1)/(select count(*) from v$bh)) *100 c3
6 from
7 dba_objects o,
8 v$bh bh
9 where
10 o.object_id = bh.objd
11 and
12 o.owner not in ('SYS','SYSTEM')
13 group by
14 owner,
15 object_name
16 order by
17 count(1) desc
18 ;
C0 C1 C2 C3
--------------- ------------------------------ ---------- ----------
PLSQLDEV STANDARD_CITY 17290 72.5860621
DBOWNER MSG_LOG 2 0.00839630
DBOWNER COUNTRY_PK 1 0.00419815
DBOWNER PARAMETER 1 0.00419815
DBOWNER PARAMETER_PK 1 0.00419815
DBOWNER MSG_LOG_IDX1 1 0.00419815
6 rows selected
SQL>
更重要的是,这个视图记录的粒度非常细,一条记录对应了一个数据块。这对于我们做内存问题分析或分析Oracle行为时很有帮助。
下面是这个视图的结构:
字段 |
数据类型 |
说明 |
FILE# |
NUMBER |
缓存块对应的数据块所在的数据文件号。可以通过视图DBA_DATA_FILES或V$DBFILES查询 |
BLOCK# |
NUMBER |
缓存块对应的数据块编号 |
CLASS# |
NUMBER |
分类编号 |
STATUS |
VARCHAR2(1) |
缓存块的状态 FREE:空闲,没有被使用 XCUR:排斥(正在被使用) SCUR:可被共享 CR:一致性读 READ:正在从磁盘读入 MREC:处于从存储介质恢复状态 IREC:处于实例恢复状态 |
XNC |
NUMBER |
缓存块上由于和其他实例争用导致的PCM(Parallel Cache Management并行缓存管理)x to null锁的数量。这一字段已经被废弃。 |
LOCK_ELEMENT_ADDR |
RAW(4 | 8) |
缓存块上PCM锁的地址。如果多个缓存块的PCM锁地址相同,说明他们被同一锁锁住。 |
LOCK_ELEMENT_NAME |
NUMBER |
缓存块上PCM锁的地址。如果多个缓存块的PCM锁地址相同,说明他们被同一锁锁住。 |
LOCK_ELEMENT_CLASS |
NUMBER |
缓存块上PCM锁的地址。如果多个缓存块的PCM锁地址相同,说明他们被同一锁锁住。 |
FORCED_READS |
NUMBER |
由于其他实例的PCM锁锁住了该缓存块,导致当前实例尝试重新请求读该缓冲块的次数。 |
FORCED_WRITES |
NUMBER |
由于其他实例的PCM锁锁住了该缓存块,导致当前实例尝试重新请求写该缓冲块的次数。 |
DIRTY |
VARCHAR2(1) |
脏标志:Y – 块被修改过,是脏块;N – 不是脏块 |
TEMP |
VARCHAR2(1) |
是否为临时块:Y – 是;N – 否。 |
PING |
VARCHAR2(1) |
是否被ping住:Y – 是;N – 否。 |
STALE |
VARCHAR2(1) |
是否是陈旧块:Y – 是;N – 否。 |
DIRECT |
VARCHAR2(1) |
是否为直接读写块:Y – 是;N – 否。 |
NEW |
VARCHAR2(1) |
字段被废弃,始终为N |
OBJD |
NUMBER |
数据块所属对象的对象标号,可以查询dba_objects |
TS# |
NUMBER |
数据块所在的表空间号,可以查询v$tablespaces |
SGA中的共享池由库缓存(Library Cache)、字典缓存(Dictionary Cache)、用于并行执行消息的缓冲以及控制结构组成。
Shared Pool的大小由参数SHARED_POOL_SIZE决定。在32位系统中,这个参数的默认值是8M,而64位系统中的默认值位64M。最大为4G。
对于Shared Pool的内存管理,是通过修正过的LRU算法表来实现的。
下面分别介绍Shared Pool的几个组成部分。
Library Cache中包括共享SQL区(Shared SQL Areas)、PL/SQL存储过程和包以及控制结构(如锁、库缓存句柄)。
任何用户都可以访问共享SQL区(可以通过v$sqlarea访问,随后会介绍这个重要视图)。因此库缓存存在于SGA的共享池中。
Oracle会为每一条SQL语句运行(每运行一条语句Oracle都会打开一个游标)提供一个共享SQL区(Shared SQL Areas)和私有SQL区(Private SQL Areas属于PGA)。当发现两个(或多个)用户都在运行同一SQL语句时,Oracle会重新组织SQL区,使这些用户能重用共享SQL区。但他们还会在私有SQL区中保存一份这条SQL语句的拷贝。
一个共享SQL区中保存了一条语句的解析树和查询计划。在多用户系统中,Oracle通过为SQL语句使用同一共享SQL区多次运行来节省内存。
当一条新的SQL语句被解析时,Oracle从共享池中分配一块内存来存储共享SQL区。这块内存的大小与这条语句的复杂性相关。如果Shared Pool不够空间分配给共享SQL区,Oracle将释放从LRU链表中查找到最近最少使用的内存块,直到有足够空间给新的语句的共享SQL区。如果Oracle释放的是一个共享SQL区的内存,那么相应的语句在下次执行时需要再次解析并重新分配共享SQL区。而从解析语句到分配共享SQL区是一个比较消耗CPU的工程。这就是为什么我们提倡使用绑定变量的原因了。在没有使用绑定变量时,语句中的变量的数值不同,oracle就视为一条新的语句(9i后可以通过cursor_sharing来控制),重复上面的解析、内存分配的动作,将大大消耗系统资源,降低系统性能。
Oracle对于PL/SQL程序单元(存储过程、函数、包、匿名PL/SQL块和触发器)的处理过程和对单个的SQL语句的处理过程相似。它会分配一个共享区来存储被解析、编译过的程序单元。同时分配一个私有区域来存放运行程序单元的会话所指定的程序单元的参数值(包括本地变量、全局变量和包变量——这也叫做包的实例化)和用于执行程序所需的内存。如果多个用户运行同一个程序单元,则他们共享同一个共享区域,并且各自保持一份私有区域,用于用户会话中指定的变量值。
而一个PL/SQL程序单元中的每条单个SQL语句的处理过程则和上面描述的SQL语句的处理过程相同。要注意一点,尽管这些语句是从PL/SQL程序单元中来的,但是Oracle还是会为这些语句分配一块共享SQL区,同时为每个用户分配一个相应的私有SQL区。
转载自:http://www.hellodba.com/reader.php?ID=102&lang=CN