1、overview
buffer cache中缓冲了数据文件中的data blocks,是SGA的一部分,可以被所有的进程共享。为了提高性能,Server 进程一次读入多data blocks,DBWn一次写入多个data blocks到data file。
相关的初始化参数有:
DB_CACHE_SIZE:指定默认的buffer pool的size,以bytes为单位。
DB_KEEP_CACHE_SIZE:以bytes为单位,指明keep buffer pool的大小。
DB_RECYCLE_CACHE_SIZE:以bytes为单位,指明recycle buffer pool的大小。
在Oracle8i中,有以下特点:
** buffer cache的大小事由DB_BLOCK_BUFFERS * DB_BLOCK_SIZE决定的;
** 在某个时间点,buffer cache中可能存在同一个data block的多个copies。只有一个是当前实际的block。但是Server为了时间读一致性,结合使用rollback信息,满足不同的查询。
** buffer cache中的blocks通过两个lists进行管理:①LRU list;②dirty list
** buffer cache中的blocks可能有三种状态:①free buffers:其在disk和memory中是一致的,可以被重用;②dirty blocks:disk和memory中的数据不同,只有这些blocks被写入disk,才可被重用;③pinned blocks:当前正在被访问的blocks
2、buffer cache Sizing的参数(9i中)
** 支持多种大小的block,system的block大小仍用db_block_size设置(后面称其为primary block size),但其他tablespace可以有自己不同的block size。
** 默认的与primary block size相关的buffer pool通过db_cache_size设置。DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE与DB_CACHE_SIZE是独立的。
** 从9i开始对SGA的infrastructure修改变为动态的,可以不必shutdown在startup。
注:由于动态SGA的分配,也引入的新的分配单元granule。可以通过v$buffer_pool监控到buffer cache中granule的分配与回收
1)granule:在9i中,SGA组件分配回收的单位是granule。是一段连续的虚拟内存分配单位。其大小要依赖于对总SGA的估计:如果估计 SGA不足128MB,则设置为4MB,否则设置为16MB。当instance startup时,Server分配granule实体,组成SGA_MAX_SIZE的大小,并分配个SGA的不同组件。最小的SGA中要有3个 granules,分别拥有redo buffer、data buffer cache和shared pool。dba可以通过alter system动态的增加SGA的某个组件的memory大小,但是必须确保有足够的free granules方可成功;memory granules不会被自动释放从而满足其他组件memory增加的需求,可以减小某些组件的memory granules,但是缩减granules必须确保是未使用的,方可成功。在动态添加组件memory时,必须注意:新的cache sizes必须是granule size的整数倍;总的SGA size不可超过MAX_SGA_SIZE;DB_CACHE_SIZE不能设置为0(注意这是9i中,而我现在安装的是11g,情况有所不同啊)
2)动态buffer cache的advisory parameter:通过设置db_cache_advice参数为on,可以提供buffer cache size的合并和预测统计数据,从而辅助DBA调节buffer cache。db_cache_advice的可以设置为:off关闭advisory,并收回相应的memory;ready,关闭advisory, 但保留其memory;on,打开advisory,从而引起一定的cpu和memory开销。为了避免从off过渡到on时引起的ORA-4031 err,需要现将其设置为ready。
3)buffer cache advisory收集的数据信息主要可以通过v$db_cache_advice视图显示
select size_for_estimate, buffers_for_estimate, estd_physical_read_factor,estd_physical_reads
from v$db_cache_advice where name=’DEFAULT’
and block_size = (select value from v$parameter where name = ‘db_block_size’)
and advice_status = ‘ON’;
4)管理database buffer cache
①服务器进程和database buffer cache:当server需要申请一个block时,需要一些步骤:
i)server通过hash函数检查被请求的block是否已经在buffer cache中了。如果被找到了,则将其从LRU list中移动到尾部。这将是逻辑读。如果没被找到,server 进程需要将block从data file中读入。
ii)在从data file中读入时,server 进程将先查找LRU list,找到一个free block。
iii)当查找LRU list时,server 进程同时会将相应的dirty block移动到dirty list中。
iv)如果dirty list超过了其threshold size,server将给DBWn发信号,让其flush在dirty list中的 dirty blocks到data file中。如果server在查找的threshold范围内找不到空闲的block时,DBWn也会受到类似信号,直接将LRU list中的block写入data file。
v)当空闲块被找到之后,server将相应的block读入空闲块。并将其放入LRU list的尾部。
vi)如果block不一致,server将通过当前block和rollback segments重建一个早期版本。
vii)此外,对于DWRn进程,每过3秒,会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
viii)当LGWR进程发起checkpoint signals时,DWRn也会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
ix)当发出命令alter tablespace offline或是进行在线备份时,DBWn也会先将LRU list中的dirty blocks移动到dirty list中,随后将dirty list中的blocks写入data file。
x)在删除object时,DBWn会先将与该object有关的dirty blocks写入磁盘。
xi)在正常的normal、immediate、transactional shutdown时,也会flush data buffer。
2、data buffer size的调节
1)调节的目标是提高data cache中的命中率,从而减少实际的物理I/O。
2)诊断的工具主要是观察cache的命中率(使用v$sysstat和utlbstat.sql与utlestat.sql等)和v$db_cache_advice
select name,value from v$sysstat
where name in (’session logical reads’, ‘physical reads’,
‘physical reads direct’,'physical reads direct (lob)’);
• physical reads: Number of blocks read from disk
• physical reads direct: Number of direct reads, does not require the cache
• physical reads direct (lob): Number of direct reads of large binary objects
• session logical reads: Number of logical read requests
命中率 = 1- (physical reads – physical reads direct – physical reads direct (lob)) / session logical reads
由于v$sysstat中的数据是自instance startup后的累计数据,所以在startup不久就进行此查询获得的结果是没有太大意义的。
v$buffer_pool描述了multiple buffer pools的情况,v$buffer_pool_statistics显示了各个pool的统计情况
select name, physical_reads, db_block_gets,consistent_gets from v$buffer_pool_statistics;
v$bh:描述了保存在cache中的数据blocks
3)tuning:
改变cache的命中率,DBA可以:
①当出现下面的情况时,可以考虑增加buffer cache size:
* cache的命中率不足90%
* 有足够的memory,不会引起额外的缺页现象
* 之前对cache的增加有较好的收效
②如果是由于data的访问特点造成了较低的命中率,可以考虑为不同的blocks使用多buffer pools,并适当的将table配置缓冲到cache中
③此外,对于sorting和parallel reads,如果可以的话,避免其读入cache。
需要注意的是:还需考虑OS的caching的影响。
4)对于命中率主要受到数据访问方式的影响
* 全表扫描
* data和application的设计
* large table的随机访问
* cache的不均匀分布
5)对于cache命中率的评估:
* 如果上一次对data buffer cache的增加没有活动较好的收效,就不要继续对其增加。
* 当查看命中率时,要明确:在全表扫描时遇到的blocks并没有放入到LRU的head部分,所以重复扫描不会造成blocks的缓冲
* 由于设计和应用层造成的重复扫描某个大表时,将会造成性能问题。所以建议尽量在一次读取数据,并适当建立索引。
6)使用multiple buffer pools:当使用multiple buffer pools方法时,objects被分配到那个pool要依靠其访问的方式。有三类buffer pools(我记得在11g中更灵活,不止三类了):
* keep:此类pool用于存放可能被reused的对象。
* recycle:该pool被用于存放reused可能性较小的blocks。
* default:同single buffer cache中的cache是一致的。
主要是通过DB_CACHE_SIZE, DB_KEEP_CACHE_SIZE和DB_RECYCLE_CACHE_SIZE参数设置的。它们都是动态的。在9i中其latches是自动分配 的。在8i中需要用db_block_lru_latches分配,一般是至少每50个blocks分配一个latch。
在使用multiple buffer pools时,可以使用如下sql语句:
CREATE INDEX cust_idx .. STORAGE (BUFFER_POOL KEEP);
ALTER TABLE customer STORAGE (BUFFER_POOL RECYCLE);
ALTER INDEX cust_name_idx STORAGE (BUFFER_POOL KEEP);
当发出alter命令来修改buffer pool时,之前的blocks仍保存在原有的buffer中,新load的才会被cache到新buffer pool中。
因为buffer pool是以segment为单位分配的,有多个segments组成对象就可能被缓冲到不同的buffer pools中。
7)keep buffer pool的使用:在确定keep pool大小时,可以在设计时考虑要把那些object放入该buffer,然后求和即可。具体可以如下:
analyze table hr.countries estimate statistics;
select table_name, blocks from dba_table where owner = ‘HR’ and table_name = ‘COUNTRIES’;
具体可以编写脚本先后对DBA_TABLES, DBA_TAB_PARTITIONS, DBA_INDEXES和DBA_CLUSTERS进行analyze。并根据访问的特性,将部分对象分对象所需要的blocks加总计算。
8)对recycle pool的设置,不要设置过小,以免在事务或SQL还没有被执行完,就已经被换出了。
对其进行监控、并确定其size的工具可以使用v$sysstat中的物理读(physical reads)的统计信息,此外可以使用v$cache视图,它需要在sys下运行catparr.sql脚本进行创建。
v$cache视图从object的角度对buffer pool的blocks的占用进行了统计。其实v$cache是为了Oracle parallel server(OPS)而发布的,在执行catparr.sql时,还创建了其他只在OPS中才有用的视图。它还映射了DB object在datafile中的 extents。当创建了新的object后,需要重新运行该脚本。
在决定recycle pool大小时,可先令recycle pool disable;运行catparr.sql;在DB使用高峰期,运行下述语句计算每个object占用了多少blocks:
select owner#, name, count(*) blocks from v$cache group by owner#, name;
根据不同对象的访问特点,确定哪些应该被放入recycle pool并加总这些对象所占用的blocks,这里我用rcb来表示这个数。分配rcb/4大小的recycle pool。
9)跟踪物理读的方法有很多:用调节工具如Oracle trace manager、sqlplus autotrace或是tkprof运行sql都可以跟踪其执行时的物理读。此外可以查看视图v$sess_io。例如:
select s.username, io.block_gets, io.consistent_gets, io.physical_reads
from v$sess_io io, v$session s where io.sid = s.sid;
10)计算multiple pools下的命中率,可以使用视图v$buffer_pool_statistics
select name, 1-(physical_reads/(db_block_gets+consistent_gets)) “hit_ratio”
from v$buffer_pool_statistics where db_block_gets + consistent_gets > 0;
11)在考虑不同的object使用何种pool时,可从下面的观点出发:
** 对于keep pool:blocks将被频繁使用;segments的大小应该小于default buffer pool大小的10%
** recycle pool:在所属的transaction之外将很少被reused;segment的大小是default buffer pool两倍之多
12)将table caching:如果server通过全表扫描获得数据,blocks将被放到LRUlist的尾部,并可能会很快因缺少free blocks被换出。对此可以选择将整个表cache到list的最近经常使用的部分。具体可以在create table时使用cache关键字,或alter table使用cache,或使用cache的暗示。但是如果将太多的table放入LRU list的most recently used端,可能会使buffer cache非常拥挤。
13)其他cache performance indicators
①select name, value from v$sysstat where name = ‘free buffer inspected’;
如果此获得的等待统计很大,并不断增加需要考虑增加buffer pool。其表示了在查找free buffer是skipped的buffer。之所以skipped,是由于dirty或pinned。
②select event, total_waits from v$system_event where event in (‘free buffer waits’, ‘buffer busy waits’);
除了v$system_event,也可从v$session_wait视图。buffer busy wait表示有多个进程尝试同时访问buffer cache中的部分buffers。通过v$waitstat视图可以查看所有不同buffer被等待统计数据。buffer busy wait中包含的类型有data block、segment header、undo header和undo block。如果在v$waitstat视图中:
* data block(tables或indexes的contention)较大:查看sql是否正确使用了索引;查看是否存在right-hand- indexes的情况(例如索引上的数据是由sequence产生);考虑是否使用segment-space管理或是增加free lists避免多个进程同时向一个block中insert。
* undo header:显示了在回滚段header上冲突:对此如果不使用自动的undo管理,则尝试增加更多的rollback segments。
* undo block:显示了在rollback segment block的冲突:如果不使用自动undo的管理,考虑增大rollback segment的sizes。
* free buffer waits:表示server进程不能找到free buffer了,signal DWRn写入dirty blocks,这个过程引起的等待。对此,可以尝试提升DBWR的效率,另一方面可以考虑是不是buffer cache设置过小了。
引起DBWR高效工作的原因可能是:i/o系统慢;i/o可能在等待某些资源,如latches;buffer cache太小了,造成DBWR需要不断写入脏数据;buffer cache太大了,一个DBWR进程迅速的无法释放足够的buffer。对此,可以进一步查看等待DBWR的session,获知具体的问题。
14)free list:它为每个对象维护一个blocks list用于数据的insert,free lists的数量是可以动态设置的。但是对于单核cpu的系统,使用多free lists的好处不大。调节free list的目的是可以减少insert时对free lists的争用冲突。当使用automatic free space management时,Oracle使用bitmap存储free-list的信息,在数据库上降低了冲突,free lists就可以不用使用了。
** 诊断free list的冲突的存在:
如上,通过v$session_wait获得等待时间具体在等待哪一个block,通过v$waitstat中class为segment header显示了等待freelist的数据,v$system_event视图中event字段为’buffer busy waits’的记录显示freelist的等待的整体信息。我们可以通过dba_segments表查看是那些segments需要增加 freelist。具体的查询语句如下:
select s.segment_name, s.segment_type, s.freelists,
w.wait_time, w.seconds_in_wait, w.state
from dba_segments s, v$session_wait w
where w.event=’buffer busy waits’
and w.p1 = s.header_files and w.p2 = s.header_block;
对freel ist的修改可以使用alter table语句进行动态修改,但是对于自动segment空间管理的模式下是不能对freelist的数量进行修改的。
对于降低buffer busy waits可采取的措施有:
** 对于data blocks:适当改变pctfree或pctused;查看是否有right-hand index;增大initrans的值,降低每个block中存放的记录的数量。
** 对于segment header:使用free lists或增加free lists的数量,使用free list groups。
** 对free list blocks:增加更多的free lists。(在Oracle Parallel Server中,应该确保每个instance有自己的free list group)
15)自动管理空闲空间。从9i开始,可以使用位图对空闲和使用的blocks使用自动空间管理,与free list相比,性能更好。它只能在创建tablespace时指明,此后,建立在该表空间上的所有segment都将以自动空间管理方式管理。
create tablespace tsp datafile ‘/path/datafile.dbf’ size nM
extent management local segment space management auto;