上篇中我们分析了buffer cache的原理和子池划分。本篇来探讨keep池的使用细节。
5、子池对象定义和特性——Keep池
Keep池的使用有一些设置的因素。
SQL> alter system set db_keep_cache_size=10M;
System altered
SQL> select component, current_size, min_size, max_size from v$sga_dynamic_components where component in ('DEFAULT buffer cache','KEEP buffer cache','RECYCLE buffer cache');
COMPONENT CURRENT_SIZE MIN_SIZE MAX_SIZE
------------------------------ ------------ ---------- ----------
DEFAULT buffer cache 62914560 62914560 0
KEEP buffer cache 12582912 0 0
RECYCLE buffer cache 0 0 0
Keep池的定义,首先是从数据表开始。我们首先在scott用户下,设置一个数据表t_keep,使用storage子句定义为KEEP池对象。
--注意,此处是scott用户
SQL> show user;
USER 为 "SCOTT"
SQL> create table t_keep as select * from dba_objects;
Table created
SQL> alter table t_keep cache;
Table altered
SQL> alter table t_keep storage(buffer_pool keep);
Table altered
调用命令:
(篇幅原因,有省略…)
--第一次调用
SQL> select count(*) from t_keep;
已用时间: 00: 00: 01.73
统计信息
----------------------------------------------------------
179 recursive calls
0 db block gets
715 consistent gets
699 physical reads
SQL> select count(*) from t_keep;
已用时间: 00: 00: 00.01
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
698 consistent gets
0 physical reads
那么,两次调用中,第二次调用执行时间短(0.01s),而且没有发生物理读。缓存的t_keep数据表块是不是放在keep池中了呢?我们在MOS [ID 373472.1]中,找到一个脚本,用来判断对象缓冲池的情况。我们进行适当改写,如下:
select decode(pd.bp_id,1,'KEEP',2,'RECYCLE',3,'DEFAULT',
4,'2K SUBCACHE',5,'4K SUBCACHE',6,'8K SUBCACHE',
7,'16K SUBCACHE',8,'32K SUBCACHE','UNKNOWN') subcache,
bh.object_name,
bh.blocks
from x$kcbwds ds,
x$kcbwbpd pd,
(select /*+ use_hash(x) */ set_ds,
o.name object_name,
count(*) BLOCKS
from obj$ o,
x$bh x
where o.dataobj# = x.obj
and x.state !=0 --and o.owner# !=0
group by set_ds,o.name) bh
where ds.set_id >= pd.bp_lo_sid
and ds.set_id <= pd.bp_hi_sid
and pd.bp_size != 0
and ds.addr=bh.set_ds
我们调用该语句,获得结果如下:
Started spooling to d:\dbbuffer.log
SUBCACHE OBJECT_NAME BLOCKS
------------ ------------------------------ ----------
KEEP T_KEEP 694
Stopped spooling to d:\dbbuffer.log
说明,的确该数据表是缓存在了keep池中。
在实验中,笔者发现两个值得关注的细节。首先就是sys用户数据表的缓存情况。下面实验:
SQL> show user;
User is "SYS"
SQL> alter table t cache;
Table altered
SQL> alter table t storage(buffer_pool keep);
Table altered
之后执行语句,将数据块加载到缓存中:
SQL> select count(*) from t;
已用时间: 00: 00: 01.16
统计信息
----------------------------------------------------------
124 recursive calls
0 db block gets
1399 consistent gets
1387 physical reads
0 redo size
SQL> select count(*) from t;
已用时间: 00: 00: 00.01
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
1389 consistent gets
0 physical reads
但是,调用脚本后,却发现数据表T被缓存在Default池中。
SQL>
Started spooling to d:\dbbuffer.log
SUBCACHE OBJECT_NAME BLOCKS
------------ ------------------------------ ----------
DEFAULT T 1379
Stopped spooling to d:\dbbuffer.log
说明:对于sys用户的数据表,可以定义缓存keep池。但是实际进行buffer block缓存的时候,只能缓存到Default池内。
第二个细节在于,我们定义的keep池大小,通常是有限的。那么,如果数据表超过设置的keep池容量,会有什么影响呢?我们刚刚在scott下建立的数据表,体积大约有6M。但是,我们设置的keep池大小,有12M。
SQL> col owner for a10;
SQL> col segment_name for a20;
SQL> select owner, segment_name, bytes/1024/1024 from dba_segments where segment_name='T_KEEP';
OWNER SEGMENT_NAME BYTES/1024/1024
---------- -------------------- ---------------
SCOTT T_KEEP 6
SQL> show parameter keep;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
buffer_pool_keep string
control_file_record_keep_time integer 7
db_keep_cache_size big integer 12M
增加t_keep数据表大小,让他超过keep池容量。那么,keep池必然是放不下整个数据表的所有块的。这个时候,Oracle的行为是什么样子呢?我们增加到22M。
--增大体积之后
SQL> select owner, segment_name, bytes/1024/1024 from dba_segments where segment_name='T_KEEP';
OWNER SEGMENT_NAME BYTES/1024/1024
---------- -------------------- ---------------
SCOTT T_KEEP 22
下面我们调用三次实验语句,观察逻辑IO和物理IO情况。
--第一次调用
SQL> select count(*) from t_keep;
已用时间: 00: 00: 01.03
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
2770 consistent gets
2766 physical reads
0 redo size
--第二次调用
SQL> select count(*) from t_keep;
已用时间: 00: 00: 01.03
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
2770 consistent gets
2765 physical reads
0 redo size
--第三次调用
SQL> select count(*) from t_keep;
已用时间: 00: 00: 01.31
统计信息
----------------------------------------------------------
0 recursive calls
0 db block gets
2770 consistent gets
2765 physical reads
我们发现,三次调用的执行时间、逻辑物理IO相同。每次都会有一定的物理IO读取。我们观察一下T_KEEP数据表块在内存buffer cache中的情况。
SQL>
Started spooling to d:\dbbuffer.log
SUBCACHE OBJECT_NAME BLOCKS
------------ ------------------------------ ----------
KEEP T_KEEP 1497
Stopped spooling to d:\dbbuffer.log
发现,始终只有在keep池中的1497个数据块。说明:如果一个数据表不能将所有的数据块放置在设置的keep池中,其他多余的数据块不能缓存在其他池中,而是剔除内存。每次查询的时候进行物理IO操作。
经过分析,我们可以获得keep池的使用和约束。通常,如果数据表很小,而且应用高频度访问,没有其他优化空间的情况下,可以考虑将该数据表缓存在keep池中。缓存Keep池的主要作用在于减少物理IO。
最后,我们看看recycle的一些特征。
来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-714776/,如需转载,请注明出处,否则将追究法律责任。
转载于:http://blog.itpub.net/17203031/viewspace-714776/