Oracle 記憶體管理

li__hl8888發表於2016-11-08


 

Oracle有3個主要的記憶體結構:
系統全域性區(System Global Area,SGA)是一個很大的共享記憶體段,幾乎所有Oracle程式都要訪問這個區中的某一點。
程式全域性區(Process Global Area,PGA)是一個程式或執行緒專用的記憶體,其他程式/執行緒不能訪問。
使用者全域性區(User Global Area,UGA):這個記憶體區與特定的會話相關聯,儲存會話的狀態。如果使用共享伺服器,UGA 就在SGA 中分配;如果使用專用伺服器,UGA就會在PGA(即程式記憶體區)中。
Oracle中有2種辦法管理記憶體。一種是自動管理,一種是手動管理。
自動管理有2個層次,
第一個層次,需要設定2個引數(sga_target和pga_aggregate_target),以確定SGA和PGA的大小;
第二個層次(11g之後),只需要設定memory_target這一個引數,Oracle自動確定所有記憶體區大小。
memory_target引數->


PGA
PGA記憶體管理受資料庫初始化引數WORKAREA_SIZE_POLICY的控制,而且可以在會話級修改。在Oracle9i Release 2 及以上版本中,這個初始化引數預設為AUTO,表示自動PGA記憶體管理。

如果引數WORKAREA_SIZE_POLICY是MANUAL,則啟動手動PGA記憶體管理,以下引數對PGA大小的影響最大:
·SORT_AREA_SIZE:在資訊換出到磁碟之前,用於對資訊排序的RAM總量。
·SORT_AREA_RETAINED_SIZE:排序完成後用於儲存已排序資料的記憶體總量。這部分記憶體一般從UGA中分配。
也就是說,如果SORT_AREA_SIZE是512 KB,SORT_AREA_RETAINED_SIZE是256 KB,那麼伺服器程式最初處理查詢時會用512 KB的記憶體對資料排序。等到排序完成時,排序區會“收縮”為256 KB,這256 KB記憶體中放不下的已排序資料會寫出到臨時表空間中。
·HASH_AREA_SIZE:伺服器程式在記憶體中儲存雜湊表所用的記憶體量。雜湊聯結時會使用這些雜湊表結構,通常把一個大集合與另一個集合聯結時就會用到這些結構。兩個集合中較小的一個會雜湊到記憶體中,雜湊區中放不下的部分都會透過聯結鍵儲存在臨時表空間中。

如果WORKAREA_SIZE_POLICY設定為AUTO,PGA_AGGREGATE_TARGET有一個非0值,就會使用自動PGA記憶體管理。

對於OLTP應用,傾向於使用自動PGA 記憶體管理。手動記憶體管理則適用於大型批處理作業(它們在特殊的時段執行,此時它們是資料庫中惟一的活動)。


SGA
可以透過
select pool, name, bytes from v$sgastat order by pool, name;
語句瞭解SGA的詳細狀況。
主要的SGA元件有:
1)固定SGA(fixed SGA)
無法控制固定SGA的大小,不過固定SGA通常都很小。可以把這個區想成是SGA中的“自啟”區,Oracle在內部要使用這個區來找到SGA 的其他區。

2)重做緩衝區(redo buffer)
線上重做日誌在寫至磁碟之前,要在重做緩衝區中臨時快取這些資料。
由於記憶體到記憶體的傳輸比記憶體到磁碟的傳輸快得多,因此使用重做日誌緩衝區可以加快資料庫的操作。

3)塊緩衝區快取(block buffer cache)
Oracle從磁碟讀取資料庫塊之後,將資料庫塊寫至磁碟之前,就會把這些資料庫塊儲存在塊緩衝區快取(block buffer cache)中。這是SGA中一個很重要的區。
SGA中各個段的已快取塊放在3個位置上:
·預設池(default pool):所有段塊一般都在這個池中快取。
·保持池(keep pool):按慣例,訪問相當頻繁的段會放在這個候選的緩衝區池中。
·回收池(recycle pool):按慣例,訪問很隨機的大段可以放在這個候選的緩衝區池中。
實際上,這3個池會以大體相同的方式管理塊;將塊老化或快取的演算法並沒有根本的差異。這樣做的目標是讓DBA能把段聚集到“熱”區(hot)、“溫”區(warm)和“不適合快取”區(do not care to cache)。
理論上講,預設池中的物件應該足夠熱(也就是說,用得足夠多),可以保證一直呆在快取中。快取會把它們一直留在記憶體中,因為它們是非常熱門的塊。可能還有一些段相當熱門,但是並不太熱;這些塊就作為溫塊。為了保持這些溫段的塊得到快取,可以將這些段分配到保持池,力圖讓溫塊在緩衝區快取中停留得更久。將“不適合快取”段分配到回收池,讓回收池相當小,以便塊能快速地進入快取和離開快取(減少管理的開銷)。
預設池、保持池和回收池只快取具有預設大小的塊((最初建立資料庫時使用的塊大小)。
如果要在資料庫中使用非預設的塊大小,需要配置一個緩衝區池來儲存這些塊。
例如,當前資料庫預設塊大小為8K,如如果執行
create tablespace ts_16k datafile 'c:\ts_16k.dbf' size 2m blocksize 16k;
試圖建立1個16K的塊大小的tablespace,會得到1個"ORA-29339: 表空間塊大小 16384 與配置的塊大小不匹配"的錯誤。說明需要建立1個16K塊大小的塊緩衝區。
可以設定DB_16K_CACHE_SIZE 引數,並重啟資料庫。
也可以縮小另外的某個SGA元件,從而在現有的SGA中騰出空間來建立一個16 KB的快取。
或者,如果SGA_MAX_SIZE 引數大於當前的SGA 大小,可以直接分配一個16 KB的快取。
之後就可以成功建立這個16K塊大小的tablespace。

4)共享池(shared pool)
共享池就是Oracle快取一些“程式”資料的地方,系統引數,資料字典快取,已解析的查詢計劃等也儲存在這裡。
共享池中的記憶體根據LRU(最近最少使用)的原則來管理,類似於塊緩衝區快取。

Oracle 將已解析、已編譯的SQL 連同其他內容儲存在共享池(shared pool)中。
這就要求開發人員在大多數情況下都會使用繫結變數(bind variable)。例如:
select * from emp where empno = :empno;
這個查詢只編譯一次,隨後會把查詢計劃儲存在一個共享池(庫快取)中,以便以後獲取和重用這個查詢計劃。
如果你確實想讓Oracle緩慢地執行,甚至幾近停頓,只要根本不使用繫結變數就可以辦到:
select * from emp where empno = 123;
如果在查詢中使用直接量(常量),那麼每個查詢都將是一個全新的查詢,在資料庫看來以前從未見過,必須對查詢進行解析、限定(命名解析)、安全性檢查、最佳化等。簡單地講,就是你執行的每條不同的語句都要在執行時進行編譯。
與重用已解析的查詢計劃(稱為軟解析,soft parse)相比,解析包含有硬編碼變數的語句(稱為硬解析,hard parse)需要的時間更長,而且要消耗更多的資源。
更重要的因素是庫快取所用的閂定(latching)機制。硬解析一個查詢時,資料庫會更長時間地佔用一種低階序列化裝置,這稱為閂(latch),這些閂能保護Oracle共享記憶體中的資料結構不會同時被兩個程式修改(否則,Oracle 最 後會得到遭到破壞的資料結構),而且如果有人正在修改資料結構,則不允許另外的人再來讀取。對這些資料結構加閂的時間越長、越頻繁,排隊等待閂的程式就越多,等待佇列也越長。你可能開始獨佔珍貴的資源。資料庫中只要有一個應用表現不佳,就會嚴重地影響所有其他應用的效能。如果只一個小應用沒有使用繫結變數,那麼即使其他應用原本設計得很好,能適當地將已解析的SQL 放在共享池中以備重用,但因為這個小應用的存在,過一段時間就會從共享池中刪除已儲存的SQL。這就使得這些設計得當的應用也必須再次硬解析SQL。
不使用繫結變數是導致效能問題的一個主要原因,也是阻礙可擴縮性的一個重要因素。

不使用繫結變數的另外一個影響,就是安全性,容易受到“SQL隱碼攻擊”攻擊。

Oracle 8.1.6 增加了一個新引數CURSOR_SHARING=FORCE。如果你願意,這個特性會實現一個自動繫結器(auto-binder)。如果有一個查詢編寫為SELECT * FROM EMPWHERE EMPNO = 1234,自動繫結器會悄無聲息地把它改寫成SELECT * FROM EMP WHERE EMPNO = :x。這確實能動態地大大減少硬解析數,並減少前面討論的庫閂等待時間——但是它可能有一些副作用。從長遠來看,要儘可能地使用繫結變數,而在需要時才使用常量,這才是正確的做法。

5)大池(large pool)
大池用於大塊記憶體的分配,共享池不會處理這麼大的記憶體塊。
共享池根據LRU來管理記憶體,這對於快取和重用資料很合適。大塊記憶體分配則是得到一塊記憶體後加以使用,然後就到此為止,沒有必要快取這個記憶體。
大池中分配的記憶體在堆上管理,與C語言透過malloc()和free()管理記憶體很相似。一旦“釋放”了一塊記憶體,它就能由其他程式使用。在共享池中,實際上沒有釋放記憶體塊的概念。只是分配記憶體,然後使用,再停止使用而已。過一段時間,如果需要重用那個記憶體,Oracle會讓你的記憶體塊老化。

大池專門用於以下情況:
·共享伺服器連線,用於在SGA 中分配UGA 區。
·語句的並行執行,允許分配程式間的訊息緩衝區,這些緩衝區用於協調並行查詢伺服器。
·備份,在某些情況下用於RMAN磁碟I/O 緩衝區。

6)Java池(java pool)
用於支援在資料庫中執行Java。

7)流池(stream pool)
用於支援流(一個資料庫共享/複製工具)。

對 SGA 整體大小影響最大的引數如下:
·JAVA_POOL_SIZE:控制Java 池的大小。
·SHARED_POOL_SIZE:在某種程度上控制共享池的大小。
·LARGE_POOL_SIZE:控制大池的大小。
·DB_*_CACHE_SIZE:控制各個可用的緩衝區快取的大小。
·LOG_BUFFER:在某種程度上控制重做緩衝區的大小。
·SGA_TARGET:Oracle 10g及以上版本中用於自動SGA記憶體管理。
·SGA_MAX_SIZE:用於控制資料庫啟動並執行時SGA可以達到的最大大小。
可以透過查詢v$sgainfo檢視來檢視SGA各個元件大小,以及是否可以調整(RESIZEABLE)。

如果採用手動SGA記憶體管理,需要設定上述各個引數;
如果採用自動SGA記憶體管理,只需把SGA_TARGET 引數設定為所需的SGA大小,資料庫例項會根據工作負載條件在執行時分配和撤銷(釋放)各個SGA 元件。

關閉資料庫時,資料庫會把各個SGA元件大小透過一些首部帶下劃線引數(__DB_CACHE_SIZE、__JAVA_POOL_SIZE、__LARGE_POOL_SIZE 和__SHARED_POOL_SIZE等)記錄到儲存引數檔案(SPFILE)中,並在啟動時再使用這些值來設定各個區的預設大小。
另外,如果知道上述4個區中某個區的最小值,那麼除了設定SGA_TARGET 外,還可以設定這個引數。例項會使用你的設定作為下界(即這個區可能的最小大小)。

11g之後,Oracle提供了自動記憶體管理,只需要設定memory_target這一個引數,Oracle自動確定所有記憶體區大小。這種情況下,SGA_TARGET和PGA_AGGREGATE_TARGET這2個引數就被用來設定下界。
Oracle會把SGA和PGA的最優設定儲存到spfile的__sga_target和__pga_aggregate_target這2個引數中。

不論是使用自動記憶體管理還是手動記憶體管理,各個池的記憶體以一種稱為顆粒(granule)的單位來分配。
透過查詢V$SGA_DYNAMIC_COMPONENTS,可以檢視各個池所用的顆粒大小。例如:
select component, granule_size from v$sga_dynamic_components;

本篇文章來源於 Linux公社網站()  原文連結:

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

相關文章