Oracle 10g 可以自動共享內存管理
是不是很難準確地分配不同的池所需的內存數?自動共享內存管理特性使得自動將內存分配到最需要的地方去成為可能。無論您是一個剛入門的 DBA 還是一個經驗豐富的 DBA,您肯定至少看到過一次類似以下的錯誤:
ORA-04031:unable to allocate 2216 bytes of shared memory ("shared pool"... ...
或者這種錯誤:
ORA-04031:unable to allocate XXXX bytes of shared memory
("large pool","unknown object","session heap","frame")
或者可能這種錯誤:
ORA-04031:unable to allocate bytes of shared memory ("shared pool",
"unknown object","joxlod:init h", "JOX:ioc_allocate_pal")
第一種錯誤的原因很明顯:分配給共享池的內存不足以滿足用戶請求。(在某些情況下,原因可能不是池本身的大小,而是未使用綁定變量導致的過多分析造成的碎片,這是我很喜歡的一個主題;但目前讓我們把重點放在手頭的問題上。)其它的錯誤分別來自大型池和 Java 池的空間不足。
您需要解決這些錯誤情況,而不作任何與應用程序相關的修改。那么有哪些方案可選呢?問題是如何在Oracle 例程所需的所有池之間劃分可用的內存。
餡餅怎么分?
正如您所了解的,一個 Oracle 例程的系統全局區域 (SGA) 包含幾個內存區域(包括緩沖高速緩存、共享池、Java 池、大型池和重做日志緩沖)。這些池在操作系統的內存空間中占據了固定的內存數;它們的大小由 DBA 在初始化參數文件中指定。
這四個池(數據庫塊緩沖高速緩存、共享池、Java 池和大型池)幾乎占據了 SGA 中所有的空間。(與其它區域相比,重做日志緩沖沒有占據多少空間,對我們這里的討論無關緊要。)作為 DBA,您必須確保它們各自的內存分配是充足的。
假定您決定了這些池的值分別是 2GB、1GB、1GB 和 1GB。您將設置以下初始化參數來為數據庫例程規定池的大小。
db_cache_size = 2g
shared_pool_size = 1g
large_pool_size = 1g
java_pool_size = 1g
現在,仔細看一下這些參數。坦白講,這些值是否準確?
我相信您一定會有疑慮。在實際中,沒有人能夠為這些池指定確切的內存數 — 它們太依賴于數據庫內部的處理,而處理的特性隨時在變化。
下面是一個示例場景。假定您有一個典型的、大部分屬于 OLTP 的數據庫,并且為緩沖高速緩存分配的專用內存比為純 OLTP 數據庫(現在已經很少見了)分配的要少。有一天,您的用戶放開了一些非常大的全表掃描,以創建當天的結束報表。Oracle9i 數據庫為您提供了在線修改內存分配的功能,但由于提供的總物理內存有限,您決定從大型池和 Java 池中取出一些內存:
alter system set db_cache_size = 3g scope=memory;
alter system set large_pool_size = 512m scope=memory;
alter system set java_pool_size = 512m scope=memory;
這個解決方案能夠很好地工作一段時間,但是接著夜間的 RMAN 作業(它們使用大型池)開始了,大型池將立即出現內存不足。同樣,您從數據庫高速緩存中取出一些內存來補充大型池,以挽救這種局面。
RMAN 作業完成,然后啟動一個廣泛使用 Java 的批處理程序,接著您開始看到與 Java 池相關的錯誤。因此,您(再次)重新分配池,以滿足 Java 池和數據庫高速緩存上的內存需求:
alter system set db_cache_size = 2G scope=memory;
alter system set large_pool_size = 512M scope=memory;
alter system set java_pool_size = 1.5G scope=memory;
第二天早上,OLTP 作業恢復在線,這個循環又完全重復!
解決這種惡性循環的一種替代方法是永久設置每個池的最大需求。不過,這么做的話,您分配的總的 SGA 可能超出可用的內存 — 從而在為每個池分配的內存數不足時,將增加交換和分頁的風險。人工重新分配的方法(雖然不實際)目前看起來很不錯。
另一種替代方法是將值設為可接受的最小值。不過,當需求增長且內存不能完全滿足時,性能將受到影響。
注意在所有這些示例中,分配給 SGA 的總內存保持不變,而池之間的內存分配根據即時的需求進行修改。如果 RDBMS 將自動探測來自用戶的需求并相應地重新分布內存分配,那不是很好嗎?
Oracle 數據庫 10g 中的自動共享內存管理特性正好能夠實現這一目的。您可以決定 SGA 的總大小,然后設置一個名稱為 SGA_TARGET 的參數,這個參數決定 SGA 的總大小。SGA 內部的各個池將根據工作負載動態地進行配置。實現自動內存分配僅僅需要 SGA_TARGET 參數的一個非零值。
設置自動共享內存管理
讓我們看看該特性是如何工作的。首先,確定 SGA 的總大小。您可以通過確定現在分配了多少內存來估計這個值。
SQL> select sum(value)/1024/1024 from v$sga;
SUM(VALUE)/1024/1024
--------------------
500
此時 SGA 的當前總大小近似為 500MB,并且這個值將變為 SGA_TARGET 的值。接下來,執行語句:
alter system set sga_target = 500M scope=both;
這種方法不需要為各個池設置不同值;因而,您將需要在參數文件中使它們的值為零或全部刪除它們。
shared_pool_size = 0
large_pool_size = 0
java_pool_size = 0
db_cache_size = 0
再循環數據庫,使這些值生效。
這個人工過程還可以通過 Enterprise Manager 10g 實施。從數據庫主頁中,選擇 "Administration" 選項卡,然后選擇 "Memory Parameters"。對于人工配置的內存參數,將顯示標記為 "Enable" 的按鈕,以及所有人工配置的池的值。單擊 "Enable" 按鈕,啟用自動共享內存管理特性。企業管理器將完成剩下的工作。
在配置了自動內存分配之后,您可以利用以下命令檢查它們的大小:
SQL> select current_size from v$buffer_pool;
CURRENT_SIZE
------------
340
SQL> select pool, sum(bytes)/1024/1024 Mbytes from v$sgastat group by pool;
POOL MBYTES
------------ ----------
java pool 4
large pool 4
shared pool 148
正如您所看到的,所有的池都從 500MB 的總目標大小中自動進行分配。(參見圖 1。)緩沖高速緩存大小是 340MB,Java 池是 4MB,大型池是 4MB,共享池是 148MB。它們合起來總的大小為 (340+4+4+148=) 496MB,近似與 500MB 的目標 SGA 的大小相同。

現在假定提供給 Oracle 的主機內存從 500MB 減少為 300MB,這意味著我們必須減少總 SGA 的大小。我們可以通過減小目標 SGA 大小來反映這種變化。
alter system set sga_target = 300M scope=both;
現在查看各個池,我們可以看到:
SQL> select current_size from v$buffer_pool;
CURRENT_SIZE
------------
244
SQL> select pool, sum(bytes)/1024/1024 Mbytes from v$sgastat group by pool;
POOL MBYTES
------------ ----------
java pool 4
large pool 4
shared pool 44
占用的總大小是 240+4+4+44 = 296MB,接近于目標的 300MB。注意如圖 2 所示,當 SGA_TARGET 改變時,如何自動重新分配池。

這些池的大小是動態的。池將根據工作負載擴展,以容納需求的增長,或縮小以容納另一個池的擴展。這種擴展或縮小自動發生,無需 DBA 的干預,這與本文開頭的示例不同。讓我們暫時返回到那個場景,假定在初始分配后,RMAN 作業啟動,指示需要一個更大的大型池,大型池將從 4MB 擴展到 40MB,以容納需求。這個額外的 36MB 將從數據庫緩沖中劃出,數據庫塊緩沖將縮小,如圖 3 所示。

池的大小變化基于系統上的工作負載,因此不需要為最壞的情況調整池的大小 — 它們將根據需求的增長自動調整。此外,SGA 的總大小始終在由 SGA_TARGET 指定的最大值之內,因此不存在使內存需求的增長比例失調(這將導致分頁和交換)的風險。您可以動態地將 SGA_TARGET 增加至絕對最大值,這個絕對最大值是通過調整參數 SGA_MAX_SIZE 指定的。
哪些池不受影響?
SGA 中的一些池不受動態大小調整的影響,但是必須顯式指定這些池。其中值得注意的是非標準塊大小的緩沖池,以及 KEEP 池或 RECYCLE 池的非默認塊大小。如果您的數據庫有一個塊大小為 8K,而您想要配置 2K、4K、16K 和 32K 塊大小的池,那么您必須手動設置它們。它們的大小將保持不變;它們將不會根據負載縮小或擴展。當使用多種大小的緩沖池、KEEP 池和 RECYCLE 池時,您應當考慮這個因素。此外,日志緩沖不受內存調整的影響 — 不管工作負載如何,
posted on 2009-06-20 10:47 風 閱讀(537) 評論(0) 編輯 收藏 所屬分類: Oracle