您好,登錄后才能下訂單哦!
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狀態,因此它們容易被替換。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。