Oracle Least Recently Used Chains

eric0435發表於2019-03-28

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狀態,因此它們容易被替換。


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-2639623/,如需轉載,請註明出處,否則將追究法律責任。

相關文章