LRU Chains(or LRU lists)有它们相关的算法在过去已经修改过多次。尽管算法已经修改过,但LRU chain的功能仍然相同:为了帮助被频繁访问的buffer内置在cache中和帮助服务器进程快速地找到可被替换的buffers。任何时候单个列表都要努力地完成这两个任务,这将可能出现一些妥协。LRU chain也不例外,正如你将要发现的一样,Oracle当前的LRU算法实现的非常好,支持buffer caches超过100G的大小来满足电信与政府系统的高事务处理的要求。
在Oracle 6中,只有单个LRU chain被单个LRU chain latch保护着。在大型的OLTP系统中,DBA将与LRU chainlatch竞争进行斗争。但从Oracle 7开始,Oracle通过将单个LRU chain分割成多个小的LRU chains,每个都有一个相关的LRU chain latch来缓解这种问题。每个cache buffer存放在CBC结构中并存放在一个LRU chain或一个写列表(也叫脏列表)中。buffers不会同时存放在一个写列表与一个LRU列表中。LRU chains要比CBCs长太多。
脏buffers存放在一个LRU chain中不是问题。事实上,如果脏buffers不能存放在一个LRU chain上将会影响性能。LRU chains的一目标就是将被频繁访问的buffers保留在cache中,并且许多脏buffers也会被频繁地访问。当在数据库检查点期间,每个脏buffer将被写入磁盘并再次变为free buffer。
隐含参数_db_block_lru_latches显示实例正在使用的的LRU chains的数量。与CBCs一样,每个LRU chain latch控制着一组LRU chains的序列化。
SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ
2 from x$ksppi x, x$ksppcv y
3 where x.inst_id=USERENV(‘Instance’)
4 and y.inst_id=USERENV(‘Instance’)
5 and x.indx=y.indx
6 and x.ksppinm like ‘%&par%’;
Enter value for par: _db_block_lru_latches
old 6: and x.ksppinm like ‘%&par%’
new 6: and x.ksppinm like ‘%_db_block_lru_latches%’
NAME VALUE DESCRIB
———————- —— ——————————–
_db_block_lru_latches 640 number of lru latches
LRU Chain随着时间的推移而变化
当前的LRU chain算法被叫做touch-count算法,它使用计算频率方案在每个buffer header上设置一个数字。但是Oracle花了很多年才实现这个算法。理解Oracle的LRU算法的发展更能了解LRU chains是如何工作的,它的缺点是什么以及如何确保它们按需执行。
当LRU chains出现性能问题时,大量的LRU chain latch竞争将会出现。从Oracle算法角度来说,latch问题通常会造成服务器进程在搜索一个free buffer时持有一个lRU chain latch的时间太长。这里存在许多相互关联的原因,其解决方案也是一样。
Standard LRU Algorithm(标准LRU算法)
不管Oracle的LRU算法如何,每个Oracle LRU chain有一个最近最少使用(LRU)端,也有一个最近频繁使用(MRU)端。笼统地说,被频繁访问的buffer header将存放在靠近MRU端,并且不被频繁访问的buffer将存放在靠近LRU端。
标准LRU算法是非常简单的。当一个buffer被放入cache中或被访问时(查询或DML操作),buffer将被存放在会话相关的LRU chain(每个会话与一个LRU chain相关)的MRU端。这种想法是一个被频繁访问的buffer将被重复touched并且会被重复移动到LRU chain中的MRU端。buffer移动到LRU chain的MRU端通常叫做buffer promotion。如果一个buffer不被频繁访问,那么其它的buffer将被promoted或插入到LRU chain中,不被频繁访问的buffer将被移动到LRU chain的LRU端。
靠近每个LRU chain的LRU端可能潜伏着一个服务器进程用来查找一个可用的不被频繁访问的buffer好让刚刚从磁盘中读取来的块替换掉它。假设LRU chain是8个buffer header那么长,全表扫描会扫描8个数据块,并且每个数据块将读入Oracle cache中并且buffer headers会被放入LRU chain中。当标准LRU算法使用时,只有一个LRU chain,因此整个LRU链将被全表扫描所访问的数据块所替换。随着时间的推移包含被频繁访问的buffer已经被替换了。用户肯定会注意到性能的变化,并且IO子系统也将受到打击。当数据库大小继续增长的时候,Oracle显然不得不进行改进,所以修改了LRU算法。
Modified LRU Algorithm(修改后的LRU算法)
Oracle著名的LRU算法修改是在Oracle 6中。它是一次重大成就并且Oracle开发者确实应该对他们的高级buffer cache算法感到自豪。在这之后,它确实解决了标准LRU算法的关键问题。
修改后的LRU算法与标准LRU算法仅有的区别是对LRU chain的LRU端的几个buffer创建了一个窗口(用来存放被频繁访问的buffers)。这个窗口的大小只有几个buffers(例如,4个)并且可以通过隐含参数_small_table_threshold来进行修改。这可以确保不管对多大的表进行全表扫描都将不会对cache产生什么影响。
Oracle修改后的LRU算法对一些buffer headers创建了一个窗口,当所有全表扫描(FTS)的buffer headers被读入到buffer cache时会经过这个窗口。这确保了放在LRU chain中的MRU端的被频繁访问的buffers不会被替换掉。
与其它所有算法一样,修改的LRU算法也有限制,但这么多年来这些限制没有造成问题。然而,一旦客户开始使用Oracle来开发大型数据仓库应用程序时,两个显著的问题会出现:
.大型数据仓库有大量的索引,并且当大量索引使用范围扫描时,成千上万的索引叶子块必须被读入cache中。这个问题直到Oracle 8i,如果索引叶子块不在buffer cache中,Oracle将产生一个单块IO请求(db file sequential read)将数据块放入buffer cache。令人吃惊的是因为这不是一个多块IO请求,索引buffer被插入到LRU chain的MRU端,这破坏了开发良好的cache,现在完全存放着索引叶子块buffers。
.当数据块被请求时(基于索引叶子块),它们也会从IO子系统中(db file sequential read)被请求一次,因此再一次这些数据块被放入到LRU chain中的MRU端。当Oracle系统大小增加时,Oracle的buffer cache减少了使用性。
Oracle’s Touch-Count Algorithm
在Oracle 8.1.5中Oracle引入了一种完全修改好的LRU chain算法已经完全消除了所有LRU chain latch竞争问题。关于这种修改没有任何文档记录。发现算法改变是因为看到了新的隐含参数_db_percent_hot_default 和_db_aging_cool_count。当有新的参数出现或有旧的参数丢弃时,算法肯定有被修改。Oracle确实实现了计算机科学领域中通常所说的计数频率方案。
SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ 2 from x$ksppi x, x$ksppcv y 3 where x.inst_id=USERENV('Instance') 4 and y.inst_id=USERENV('Instance') 5 and x.indx=y.indx 6 and x.ksppinm in('_db_percent_hot_default','_db_aging_cool_count'); NAME VALUE DESCRIB ----------------------------- ---------- ------------------------------------------------ _db_percent_hot_default 50 Percent of default buffer pool considered hot _db_aging_cool_count 1 Touch count set when buffer cooled
正如你所期待的,通用方法就是每次触及buffer header时递增计数器。更频繁访问的buffer headers将有更高的触及计数并且确实访问更频繁,因此buffer将被保留在buffer cache。Oracle’s touch-count算法判断buffer header是否被频繁访问是基于buffer header被触及的次数来确定的。注意FTS(全表扫描)窗口的概念将不再需要并且已经被删除了。touch-count算法有三个关键点:midpoint-insertion,touch count incrementation与buffer promotion
Midpoint Insertion
与修改后的LRU算法最根本的背离是midpoint insertion。每个LRU chain被分成hot区与cold区。当一个buffer从磁盘被读入且找到了一个free buffer,这个buffer与buffer header将替换之前的buffer与buffer header的内容然后这个buffer header被移动到LRU chain的midpoint。单块读,多块读,快速完全索引扫描或全表扫描都没有差别。buffer header不会被插入到LRU chain的MRU端,而是LRU chain的midpoint。这确保了不会因为单个对象的大量数据块被读入到buffer cache中而使用LRU chain被破坏掉。
缺省情况下,hot区与cold区各占一半。midpoint确实在中间。然而这个可以通过隐含参数_db_percent_hot_default来配置。
当其它buffer headers被插入到midpoint或被promoted(提升)时,原有的buffer headers自然地将从LRU chain的hot区移动到cold区。在一个buffer header被插入后,只有一种方式可以保留在cache很长时间就是被不断重复地promoted。
因为窗口方案用于修改的LRU算法中而不再被使用,隐含参数_small_table_threshold因此被丢弃。然而在Oracle11g中,它又再次被使用,但是用于不同的目的。从Oracle 11g开始,_small_table_threshold参数是服务器进程开始执行直接路径读的阈值。直接路径读可以提高性能因为数据块从磁盘直接读取到服务器进程的PGA内存中而不用放入buffer cache。然而,这是更自私的读取操作并且可能实际上降低性能,因为其它的服务器进程不能从IO操作中获利。
SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ 2 from x$ksppi x, x$ksppcv y 3 where x.inst_id=USERENV('Instance') 4 and y.inst_id=USERENV('Instance') 5 and x.indx=y.indx 6 and x.ksppinm like '%&par%'; Enter value for par: _small_table_threshold old 6: and x.ksppinm like '%&par%' new 6: and x.ksppinm like '%_small_table_threshold%' NAME VALUE DESCRIB ------------------------------ ------------------------------ ----------------------------------------------------- _small_table_threshold 60283 lower threshold level of table size for direct reads
假设你是一个服务器进程必须要查询一行存放在特定数据块中的记录。基于这个SQL语句与数据字典,你知道数据块的文件号与块号。如果只关心查询速度,因此希望这个数据块已经存放在buffer cache中了。为了检查数据块是否存放在buffer cache中,需要得到buffer’s buffer cache内存地址,它存放在它的buffer header中。
为了找到buffer header,必须访问CBC结构。哈希文件号与块号,它将指向一个哈希桶。基于这个哈希桶,可以查找相关的CBC latch与持有它。在几次spin后,你可能可以获得latch,因此开始你的序列化CBC搜索。第一个buffer header如果不是你想要的,并且不幸地是在这个CBC中没有第二个buffer header,因此知道buffer当前没有放入buffer cache。
释放CBC latch并执行调用给操作系统,要求访问你需要的数据块。当你正等待时,你将被告知db file sequential read等待事件。最终从操作系统接收到这个数据块并在PGA中持有它。因为没有使用直接路径读,在你或其它服务器进程访问buffer之前,buffer必须被合理地插入到buffer cache并更新所有合理结构。
你将需要一个free buffer用来在buffer cache中存放刚读取的数据块,因此你将移到LRU chain的LRU端。但在你开始扫描LRU chain之前,你必须持有并获得相关的LRU chain latch。之后当休眠时通过spinning与posting等待事件latch:cache buffers lru chains来消耗CPU,最终获得latch。从LRU chain的LRU端开始,你查看buffer header是否它是一个不被频繁访问的free buffer,得到的回答是它是不被频繁访问的buffer。那么你现在就可开始buffer替换操作。你立即pin(固定)住这个buffer header。从buffer header中,可以获得数据块对应buffer在buffer cache中的内存地址,使用刚被读取的且仍在你PGA内存中的块来替换这个free buffer,执行任何要求buffer header所要进行的修改。你维护这个LRU chain并移动buffer header到LRU chain’s midpoint,释放LRU chian latch,并unpin这个buffer header。现在任何服务器或后台进程包括你可以访问这个buffer,这将都是在一瞬间就能完成。
Touch Count Incrementation
这个概念是一个buffer header每被touch一次,它的touch count将会增加。事实上并不是这样。缺省情况下,一个buffer header的touch count只有每3秒才会增加一次。这可以用来确保buffer活动时间超过几秒才算做被频繁访问
当一个buffer被插入到buffer cache中时,它的touch count被设置为0.然而,如果buffer在短期内被重复地touch,那么touch将不会进行计数。
Oracle也允许touch count被遗漏。这将没有latch被调用(这是消除latch竞争最好的方法),并且Oracle不会pin住buffer header。不使用序列化控制,两个服务器进程可以递增与更新buffer header’s的touch count到相同的值。
假设服务器进程S100在时间T0点得到的buffer header的touch count是13,并且开始递增为14。但服务器进程S200现在在时间T1点询问这个buffer header的touch count,并且因为服务器进程S100还没有完成touch count的递增操作,所以buffer header的touch count现在仍然显示为13。服务器进程S200现在开始将touch count从13递增到14。在时间T2点,服务器进程S100将buffer header的touch count修改为14,并且在时间T3点,服务器进程S200也将buffer header的touch count修改为14。这是不是touch count递增被遗漏了?没有结构被损坏,并且touch count确实已经被递增了,但不是递增两次。如果一个buffer确实被频繁地访问,它将再次被touch。通过这种模糊实现节省的是CPU的消耗与内核代码运行量。
Buffer Promotion
没有说当一个buffer被touch后,它将会被promoted到LRU chain的MRU端。这是因为buffer header的touching与buffer header的promotion现在是两个分开的操作。当一个buffer被考虑进行promotion时,也会考虑替换它。而服务器进程与数据库写进程都可以promote buffer header,但只有一个服务器进程将替换这个buffer并且与它相关的buffer header作为一个物理读取数据块的结果。数据库写进程执行替换没有意义,因为它没有替换的内容。
在一个服务器进程从磁盘读取一个数据块之后,它必须要找到一个不被频繁访问的free buffer来存放刚被读取的数据块。服务器进程要获得适当的LRU latch,然后从LRU chain的LRU端开始扫描buffer headers。记住buffer headers存放在LRU chain中,不是buffers中。如果服务器进程遇到了一个free buffer header,那么它检查它是否被频繁访问。如果被频繁访问,服务器进程将promote这个buffer header,然后继续扫描。如果这个free buffer header不被频繁访问,服务器进程将使用从磁盘读取到的数据块来替换这个buffer,并更新buffer header,移动buffer header到LRU chain的midpoint。注意这里不需要更新CBC结构,因为buffer没有被移动,只有LRU chain上的buffer header被移动。如果服务器进程遇到一个dirty buffer header,那么检查是否是一个被频繁访问的dirty buffer header。如果dirty buffer header被频繁访问,它将promote这个buffer header并继续扫描。如果dirty buffer header不被频繁访问,服务器进程将移动这个buffer header到写列表中。如果服务器进程遇到一个被pin 住的buffer header,那将继续扫描。pin住的buffer被禁止使用。
promotion操作只要达到最低值2(_db_aging_hot_criteria)就会中断。因此当一个服务器进程或数据库写进程在询问“每个buffer的touch count数是多少?”时,它实际是问“buffer的touch count是否大于或等于_db_aging_hot_criteria?”。如果每隔几秒一个buffer就会被touch,那么它应该被保留在cache中。如果不是,它将被快速替换掉。
当一个被频繁访问的buffer被promoted时,它的生命周期将变得更困难。promotion操作的一部分是touch count被设置为0(_db_aging_stay_count)。除非buffer是一个segment header或一个consistent read(CR) buffer,否则会出现这种情况。
SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ 2 from x$ksppi x, x$ksppcv y 3 where x.inst_id=USERENV('Instance') 4 and y.inst_id=USERENV('Instance') 5 and x.indx=y.indx 6 and x.ksppinm in('_db_aging_stay_count'); NAME VALUE DESCRIB ------------------------- ------------ -------------------------------------------------------------- _db_aging_stay_count 0 Touch count set when buffer moved to head of replacement list
数据库写进程也可能promote被频繁访问的buffer headers。当一个数据库写进程处于休眠状态,它将每3秒钟被唤醒一次。每个数据库写进程都有一个属于它的写列表(dirty列表)并且它也与一个或多个LRU chain相关联。当一个LRU chain的数据库写进程被唤醒,它将检查它的写列表来查看写列表的长度是否足够执行一个IO写操作。如果数据库写进程决定构建一个写列表,它将扫描它的LRU chain来查找不被频繁访问的dirty buffer。非常像服务器进程查找free buffer那样,数据库写进程也将获得相关的LRU chain lath,从LRU chain的LRU端开始并检查buffer header是否为dirty且不被频繁访问。如果一个不被频繁访问的dirty buffer被找到,数据库写进程将会这个buffer header从LRU chain移动到它的写列表中(记住,这个buffer header仍然存放在CBC结构中,因此它能被其它进程找到)。如果写列表的长度仍然不足够执行一次IO写操作,那么数据库写进程将继续扫描它的LRU chain,查找更多的不被频繁访问的dirty buffer headers。
Hot Region to Cold Region Movement
一个buffer header的生命周期在LRU chain是从midpoint(正中间)开始的。因为其它buffer headers将被替换并且被插入到正中间,随着buffers被promoted,一个buffer header自然地将迁移到LRU chain的LRU端。promote一个buffer header的唯一方法就是buffer header标识为被频繁访问。当一个buffer跨过正中间(midpoint)时另一个显著事件会出现,那就是从hot region移动到cold region。
当一个buffer进入到cold region中时,它的touch count会被重设置为缺省值1(_db_aging_cool_count)。这有冷却hot buffer的效果,任何希望保留在cache中的buffer都不想出现这种情况。增加这个参数值将人为增加buffer值从而增加了buffer移动的可能性。因此缺省情况下,当一个buffer header进行到cold region时,它必须至少被touched一次来使其匹配promotion操作的条件(_db_aging_hot_criteria)。
SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ 2 from x$ksppi x, x$ksppcv y 3 where x.inst_id=USERENV('Instance') 4 and y.inst_id=USERENV('Instance') 5 and x.indx=y.indx 6 and x.ksppinm in('_db_aging_cool_count'); NAME VALUE DESCRIB ------------------------- --------- ------------------------------------ _db_aging_cool_count 1 Touch count set when buffer cooled SQL> select x.ksppinm NAME,y.ksppstvl value,x.ksppdesc describ 2 from x$ksppi x, x$ksppcv y 3 where x.inst_id=USERENV('Instance') 4 and y.inst_id=USERENV('Instance') 5 and x.indx=y.indx 6 and x.ksppinm in('_db_aging_hot_criteria'); NAME VALUE DESCRIB -------------------------- ---------- --------------------------------------------------------------- _db_aging_hot_criteria 2 Touch count which sends a buffer to head of replacement list
Touch Count Changes
可能会疑问为什么当一个buffer header被promoted和当它进入到cold region时Oracle要重新设置touch count。要理解这一点关键要理解中间点(midpoint)。中间点(midpoint)缺省情况下将每个LRU chain平分为hot与cold
region(_db_percent_hot_default=50),它可以被设置为0到100之间的任何数值。如果LRU chain变成一个100%的hot region,那么唯一的touch count重置将发生在buffer被promoted时。当Oracle释放出创建任何数量buffer pools的能力时,在每个pool中维护中间点(midpoint)的能力将允许高度优化和特定的LRU活动。尽管双重设置可能最初看起来比较愚蠢,但它确实有其真正的目的并为将来奠定了基础。
SQL> select '00 : '||count(*) x from x$bh where tch=0 2 union 3 select '01 : '||count(*) x from x$bh where tch=1 4 union 5 select '02 : '||count(*) x from x$bh where tch=2 6 union 7 select '03 : '||count(*) x from x$bh where tch=3 8 union 9 select '04 : '||count(*) x from x$bh where tch=4 10 union 11 select '05 : '||count(*) x from x$bh where tch=5 12 union 13 select '06 : '||count(*) x from x$bh where tch=6 14 union 15 select '07 : '||count(*) x from x$bh where tch=7 16 union 17 select '08 : '||count(*) x from x$bh where tch=8 18 union 19 select '09 : '||count(*) x from x$bh where tch=9 20 union 21 select '10 : '||count(*) x from x$bh where tch=10 22 union 23 select '11 : '||count(*) x from x$bh where tch=11 24 union 25 select '12 : '||count(*) x from x$bh where tch=12 26 union 27 select '13 : '||count(*) x from x$bh where tch=13 28 union 29 select '14 : '||count(*) x from x$bh where tch=14 30 union 31 select '15 : '||count(*) x from x$bh where tch=15 32 union 33 select '16 : '||count(*) x from x$bh where tch=16 34 / X --------------------------------------------- 00 : 1879125 01 : 697463 02 : 254482 03 : 227324 04 : 161410 05 : 141651 06 : 91699 07 : 70599 08 : 55605 09 : 25551 10 : 17181 11 : 29833 12 : 19978 13 : 13324 14 : 29006 15 : 9998 16 : 9649 17 rows selected
touch count被重新设置有重要影响。首先,这意味着touch count不会飙升到无穷大。touch count重新设置也意味着最被频繁访问的buffer headers将不需要有最高的touch counts。如果你注意到一个特定的buffer有一个较低的touch count,那么你可能捕获了一个被频繁访问的buffer,只是它可能刚刚被promoted或进入到LRU chain的cold region。事实上,最高touch count的buffer headers将存放在LRU chain的LRU端附近。
LRU Chain Contention Identification and Resolution
Oracle的LRU touch-count算法,与缺省的实例参数设置进行组合来使用微不足道的竞争来启用高性能LRU chain活动。当touch-count算法遇到压力时,这是IO和CPU活动的独特组合。
LRU chain latches命名为cache buffers lru chain。哈希chain latches被命名为cache buffer chains。命名很接近并且可能导致相当大的混乱。只要记住LRU chain latches的名字中lru就不会混乱。在Oracle 10g之前的版本中,等待事件被简化成latch free,为了判断特定的latch,需要使用v$session_wait视图中的p2列与v$latch中的latch#进行关联来进行查询。对于Oracle 10g及以后的版本,等待事件标识为latch:cache buffers lru chain。
如果不需要执行物理读来从磁盘读取数据,那么就不会存在LRU chain latch竞争,因为就不需要查找free buffer或者插入一个buffer header到一个LRU chain中。数据库写进程查找不被频繁访问的dirty buffers不会对LRU chain结构造成压力从而导致LRU chain latch的竞争。然而,任何时候一个服务器进程从磁盘读取数据块,它必须要找到一个free buffer,这将请求LRU chain活动(除了直接路径读)。如果IO读区花了10ms,那么你可能看到的是db file scattered read与db file sequential read等待事件而不是LRU chain latch竞争。但如果IO子系统返回数据块的时间少于5ms,那么压力就转移到CPU子系统了,并且这时LRU chain的活动将开始承受压力。
LRU chain latch竞争可能的结果是获取latch的问题,持有latch大长时间或者两个同时出现。如果操作系统的CPU受限,获得latch可能花费很长时间,因为没有足够的CPU周期。一旦latch被获得且LRU chain相关的内核代码被运行,如果CPU周期供应不足或者不被频繁访问的free buffers有限,LRU chain latch可能被持有很长时间足够造成严重的竞争。
因此,首先,必须要有强烈的物理读取活动。第二,IO子系统响应时间非常快,将大部分的等待时间从读取等待事件传递到LRU chain latch等待事件。这种竞争提供了许多可供组合使用解决方法:
.优化物理IO SQL语句
如果没有物理IO存在就不会有大量的LRU chain latch竞争。因此,从应用程序角度来说产,查找主要活动为执行物理块读取也就是物理IO活动的SQL语句。尽你所能地减少SQL语句的物理IO消耗。这意味着执行经典的SQL优化操作,包括使用索引,以及在性能关键时期减少顶级物理IO SQL语句的执行速度。
.增加CPU处理能力
与CBC latch竞争一样或任何其它latch竞争一样,如果有更多的CPU资源可以使用,内存管理将会花费更少的时间。这意味着latch持有时间与latch获取时间(spinning与sleeping)将被减少。增加CPU处理能力也意味着在竞争高峰期间寻找创建性方法来减秒CPU消耗。
.增加LRU latch数量
通过增加latches可以增加LRU的并发,这意味着增加隐含参数_db_block_lru_latches的值。如果有很多G的buffer cache增加latches可能是特别有效的。
.使用多个buffer pools
一种创造性策略来减少主LRU chain压力的方法就是实现keep与recycle pools。所有的buffer pools都可以增加LRUchain latches的数量。它们也使用touch-count算未能,并且有类似的touch count实例参数,比如_db_percent_hot_keep
.调用touch count实例参数
有几个可用touch count参数。但要注意,这些参数的值都很小,比如1和2。因引,即使参数从1修改为2都是相当大的改变可能导致意想不到的后果。只有在测试后将调整touch count参数作为最后的手段。
_db_percent_hot_default参数,它的缺省值为50。它表示在hot region的buffer headers的百分比。如果想要更多的buffer header存放在hot region,可以增加这个参数。减小这个参数将会给予buffer headers在遇到一个服务器进程或数据库写进程之前更多的时间来被touched。
_db_aging_touch_time参数,它的缺省值为3它是唯一能增加一个buffer header的touch count(x$bh.tch)时间窗口的方法。增加这个参数将减小突然爆发以buffer为中心活动的影响,同时会冒着贬值频繁被访问buffer的风险。
_db_aging_hot_criteria参数,它的缺省值为2。一个buffer header的touch count阈值必须满足或被超过才能被promoted(提升)。如果想一个buffer被promoted更困难,可以增加这个参数值。那么只有真正hot buffers才会被保留在cache中。
_db_aging_stay_count参数,它的缺省值为0。当一个buffer header被promoted时touch count被重设置后的值。一致性读与段头块除外。
_db_aging_cool_count参数,它的缺省值为1。当一个buffer header从hot region进入cold region时touch count被重设置后的值。减小这个参数值将使buffer header被promoted变得更困难。
_db_aging_freeze_cr参数,它的缺省值为false。使一致性读取的 buffers总是为cold状态,因此它们容易被替换。
隔三差五来一趟,每次都有新气象!