+++++buffer cache 深度解析(17)


2) 如果数据块类型为data(表或索引的 ,不是undo)上发生 busy waits等待事件,通常表明数据库里有些表或索引的段头具有频繁的活动 。
进程访问 主要有两种原因:一是获得或修改 信息;二是扩展HWM 。有三种方法可以降低该事件出现的频率:
a、增加争用对象的和 的数量 。
b、确定和之间的间隔不要太小 。
c、确保next 的尺寸不要太小 。
d、9i以后,使用ASSM特性来管理block 。
3) 如果数据块类型为undo的争用等待,表明数据库中的 太少,或者他们的 size太小,导致对于同一个 的大量更新 。如果使用了9i以后的auto undo ,则不用处理,因为会根据需要自动创建新的undo。如果是9i之前,则可以创建新的,并把它们,或者通过降低参数来减轻该等待 。
4) 如果数据块类型为undo block,说明有多个同时访问那些被更新过的block 。这是应用系统的问题,在数据库来说对此无能为力 。
4.3.3busy waits等待
在一个数据块被读入 cache之前,进程必须为该数据块获得一个对应的可用的内存数
据块 。当在LRU list上无法发现一个可用的内存数据块或者搜寻可用的内存数据块被暂停的时候,该就必须等待freewaits事件 。
从前面的描述,我们已经知道,一个需要可用内存数据块的前台进程会连续扫描LRU 链表,直到达到一个限定值(也就是隐藏参数ct所指定的值,表示已经扫描的 数量占整个LRU链表上的 的总数量,在9i中该限定值为40%) 。如果到该限定值时还没找到可用内存数据块时,该前台进程就会触发DBWR进程以便清空一些脏数据块,从而使得在辅助LRU链表上能够挂上一些可用的内存数据块 。在DBWR进程工作时,该前台进程就必须等待freewaits 。
跟踪每次对于可用的内存数据块的请求次数(记录在v$里的free),也跟踪每次请求可用的内存数据块失败的次数(记录在v$里的freewaits的) 。而v$里的free则说明为了找到可用的内存数据块所所跳过的数据块的个数,如果 cache很空,有很多空的数据块的话,则该值为0 。如果free相对free来说很高,则说明进程需要扫描更多的LRU链表上的数据块才可以找到可用的数据块 。
SQL> select *2fromv$sysstat3wherename in ('free buffer requested', 'free buffer inspected');STATISTIC# NAMECLASSVALUE---------- ----------------------------------------- ----------75 free buffer requested829053249379 free buffer inspected82983596SQL> select *2fromv$system_event3where event = 'free buffer waits';EVENTTOTAL_WAITS TOTAL_TIMEOUTS TIME_WAITED AVERAGE_WAIT TIME_WAITED_MICRO----------------- ----------- -------------- ----------- ------------ -----------------free buffer waits10034767107571710749256
可以看到,该系统的freewaits等待很少,总共等待的时间才0.476秒 。同时也可以看到,请求了(free)个可用的内存数据块,但是在这个过程中只跳过了(free)个数据块,二者相差2个数量级 。说明系统很容易就找到可用的内存数据块 。
如果一个花费了很多的时间等待freewaits等待事件的话,通常可能有以下原因:
1) 低效率的SQL语句:对于那些引起很大逻辑读的SQL语句(v$sql里的),那些SQL语句可能进行了全表扫描,索引全扫描、或者通过了不正确的索引扫描表等 。调整这些SQL语句以降低逻辑读 。
2) DBWR进程不够多:也可以通过增加DBWR 的个数来降低freewaits 。9i下,可以通过减小et参数来缩短MTTR,从而增加DBWR进程启动的次数 。然而,这也有可能引起进程等待writewaits事件 。
3) I/O子系统太慢 。
4) 延迟的块清除(block ):通常发生的情形是,晚上向数据库导入了一个很大的表 。然后早上运行应用系统时,会发现有有进程在等待 busy waits 。这是因为第一个访问该表的进程将进行一个延迟的块清除,而这会导致freewaits等待事件 。解决方法是在导入表完毕以后,执行一句全表扫描,比如通常是: count(*) from该大表 。这样在后面的进程再次访问的时候就不会产生freewaits等待事件了 。