Oracle内存结构详解(三)--管理Oracle Share Pool
生活随笔
收集整理的這篇文章主要介紹了
Oracle内存结构详解(三)--管理Oracle Share Pool
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
SGA中的共享池由庫緩存(Library Cache)、字典緩存(Dictionary Cache)、用于并行執行消息的緩沖以及控制結構組成。Shared Pool的大小由參數SHARED_POOL_SIZE決定。9i中,在32位系統下,這個參數的默認值是8M,而64位系統下的默認值位64M。最大為4G。 10g 以后可以通過SGA_TARGET 參數來自動調整。對于Shared Pool的內存管理,是通過修正過的LRU算法表來實現的。1、庫緩存(Library Cache)Library Cache中包括共享SQL區(Shared SQL Areas)、PL/SQL存儲過程以及控制結構(如鎖、庫緩存句柄)。任何用戶都可以訪問共享SQL區(可以通過v$sqlarea訪問,隨后會介紹這個重要視圖)。因此庫緩存存在于SGA的共享池中。(1) 共享SQL區和私有SQL區Oracle會為每一條SQL語句運行(每運行一條語句Oracle都會打開一個游標)提供一個共享SQL區(Shared SQL Areas)和私有SQL區(Private SQL Areas屬于PGA)。當發現兩個(或多個)用戶都在運行同一SQL語句時,Oracle會重新組織SQL區,使這些用戶能重用共享SQL區。但他們還會在私有SQL區中保存一份這條SQL語句的拷貝。一個共享SQL區中保存了一條語句的解析樹和查詢計劃。在多用戶系統中,Oracle通過為SQL語句使用同一共享SQL區多次運行來節省內存。當一條新的SQL語句被解析時,Oracle從共享池中分配一塊內存來存儲共享SQL區。這塊內存的大小與這條語句的復雜性相關。如果Shared Pool不夠空間分配給共享SQL區,Oracle將釋放從LRU鏈表中查找到最近最少使用的內存塊,直到有足夠空間給新的語句的共享SQL區。如果Oracle釋放的是一個共享SQL區的內存,那么相應的語句在下次執行時需要再次解析并重新分配共享SQL區。而從解析語句到分配共享SQL區是一個比較消耗CPU的工程。這就是為什么我們提倡使用綁定變量的原因了。在沒有使用綁定變量時,語句中的變量的數值不同,oracle就視為一條新的語句(9i后可以通過cursor_sharing來控制),重復上面的解析、內存分配的動作,將大大消耗系統資源,降低系統性能。(2) PL/SQL程序單元Oracle對于PL/SQL程序單元(存儲過程、函數、包、匿名PL/SQL塊和觸發器)的處理過程和對單個的SQL語句的處理過程相似。它會分配一個共享區來存儲被解析、編譯過的程序單元。同時分配一個私有區域來存放運行程序單元的會話所指定的程序單元的參數值(包括本地變量、全局變量和包變量——這也叫做包的實例化)和用于執行程序所需的內存。如果多個用戶運行同一個程序單元,則他們共享同一個共享區域,并且各自保持一份私有區域,用于用戶會話中指定的變量值。而一個PL/SQL程序單元中的每條單個SQL語句的處理過程則和上面描述的SQL語句的處理過程相同。要注意一點,盡管這些語句是從PL/SQL程序單元中來的,但是Oracle還是會為這些語句分配一塊共享SQL區,同時為每個用戶分配一個相應的私有SQL區。2、字典緩存(Dictionary Cache)數據字典是有關于數據庫的參考信息、數據庫的結構信息和數據庫中的用戶信息的一組表和視圖的集合,如我們常用到的V$視圖、DBA_視圖都屬于數據字典。在SQL語句解析的過程中,Oracle可以非常迅速的訪問(如果需要的話)這些數據字典,在SQL Trace中,這種對數據字典的訪問就被統計為回調(recursive calls)。因為Oracle對數據字典訪問如此頻繁,因此內存中有兩處地方被專門用于存放數據字典。一個地方就是數據字典緩存(Data Dictionary Cache)。數據字典緩存也被稱為行緩存(Row Cache),因為它是以記錄行為單元存儲數據的,而不像Buffer Cache是以數據塊為單元存儲數據。內存中另外一個存儲數據字典的地方是庫緩存。所有Oracle的用戶都可以訪問這兩個地方以獲取數據字典信息。3、共享池的內存管理通常來說,共享池是根據修正過的LRU算法來是否其中的對象(共享SQL區和數據自動記錄行)的,否則這些對象就一直保持在共享池中。如果共享池需要為一個新對象分配內存,并且共享池中沒有足夠內存時,內存中那些不經常使用的對象就被釋放掉。一個被許多會話使用過的共享池對象,即使最初創建它的進程已經結束,只要它是有用的,都會被修正過的LRU算法一直保持在共享池中。這樣就使一個多用戶的Oracle系統對SQL語句的處理和內存消耗最小。注意,即使一個共享SQL區與一個打開的游標相關,但如果它長時間沒有被使用,它還是可能會被從共享池中釋放出來。而此時如果打開的游標還需要運行它的相關語句,Oracle就會重新解析語句,并分配新的共享SQL區。當一條SQL語句被提交給Oracle執行,Oracle會自動執行以下的內存分配步驟:(1)Oracle檢查共享池,看是否已經存在關于這條語句的共享SQL區。如果存在,這個共享SQL區就被用于執行這條語句。而如果不存在,Oracle就從共享池中分配一塊新的共享SQL區給這條語句。同時,無論共享SQL區存在與否,Oracle都會為用戶分配一塊私有SQL區以保存這條語句相關信息(如變量值)。(2)Oracle為會話分配一個私有SQL區。私有SQL區的所在與會話的連接方式相關。在以下情況下,Oracle也會將共享SQL區從共享池中釋放出來:(1)當使用ANALYZE語句更新或刪除表、簇或索引的統計信息時,所有與被分析對象相關的共享SQL區都被從共享池中釋放掉。當下一次被釋放掉的語句被執行時,又重新在一個新的共享SQL區中根據被更新過的統計信息重新解析。(2) 當對象結構被修改過后,與該對象相關的所有共SQL區都被標識為無效(invalid)。在下一次運行語句時再重新解析語句。(3)如果數據庫的全局數據庫名(Global Database Name)被修改了,共享池中的所有信息都會被清空掉。(4)DBA通過手工方式清空共享池:ALTER SYSTEM FLUSH SHARED_POOL;Shared Pool能被分成幾個區域,分別被不同的latch(latch數最大為7,可以通過隱含參數_kghdsidx_count設置)保護。表x$kghlu可以查看shared pool中的LRU列表。當滿足以下條件之一時,shared pool會分為多個區,分別有不同的LRU鏈表管理:(1)在10g之前版本,如果shared pool大于128M、CPU數量大于4;(2)Oracle數據庫版本為10g這時,在x$kghlu中就會對應不同記錄。
4、保留共享池前面提到,如果Oracle解析一個 PL/SQL程序單元,也需要從共享池中分配內存給這些程序單元對象。由于這些對象本一般比較大(如包),所以分配的內存空間也相對較大。系統經過長時間運行后,共享池可能存在大量內存碎片,導致無法滿足對于大塊內存段的分配。為了使有足夠空間緩存大程序塊,Oracle專門從共享池內置出一塊區域來來分配內存保持這些大塊。這個保留共享池的默認大小是共享池的5%。它的大小也可以通過參數SHARED_POOL_RESERVED_SIZE來調整。保留區是從共享池中分配,不是直接從SGA中分配的,它是共享池的保留部分,用于存儲大塊段。Shared Pool中內存大于5000字節的大段就會被存放在共享池的保留部分。而這個大小限制是通過隱含參數_SHARED_POOL_RESERVED_MIN_ALLOC來設定的(如前面所說,隱含參數不要去修改它)。除了在實例啟動過程中,所有小于這個數的內存段永遠都不會放到保留部分中,而大于這個值的大內存段也永遠不會存放到非保留區中,即使共享池的空間不夠用的情況下也是如此。保留區的空閑內存也不會被包含在普通共享池的空閑列表中。它會維護一個單獨的空閑列表。保留池也不會在它的LRU列表中存放可重建(Recreatable關于內存段的各種狀態我們在后面的內容中再介紹)段。當釋放普通共享池空閑列表上的內存時是不會清除這些大段的,同樣,在釋放保留池的空閑列表上的大內存段時也不會清除普通共享池中內存。通過視圖V$SHARED_POOL_RESERVED可以查到保留池的統計信息。其中字段REQUEST_MISSES記錄了沒有立即從空閑列表中得到可用的大內存段請求次數。這個值要為0。因為保留區必須要有足夠個空閑內存來適應那些短期的內存請求,而無需將那些需要長期cache住的沒被pin住的可重建的段清除。否則就需要考慮增大SHARED_POOL_RESERVED_SIZE了。可以通過觀察視圖V$SHARED_POOL_RESERVED的MAX_USED_SPACE字段來判斷保留池的大小是否合適。大多數情況下,你會觀察到保留池是很少被使用的,也就是說5%的保留池空間可能有些浪費。但這需要經過長期觀察來決定是否需要調整保留池大小。保留區使用shared pool的LRU鏈表來管理內存塊,但是在做掃描時,相互是不受影響的。例如,內存管理器掃描shared pool的LRU鏈表,清出空間以分配給一個小于5000字節的內存請求,是不會清出保留區的內存塊的,相反亦然。5、將重要、常用對象保持(Keep)在共享池中根據LRU算法,一些一段時間沒有使用到的內存塊會被情況釋放。這就可能導致一些重要的對象(如一個含有大量通用算法函數的包、被cache的序列)被從內存中清除掉。這些對象可能只是間歇被使用,但是因為他們的處理過程復雜(不僅包本身重新分配內存、解析,還要檢查里面的所有語句),要在內存中重建他們的代價非常大。我們可以通過調用存儲過程DBMS_SHARED_POOL.KEEP將這些對象保持在共享池中來降低這種風險。這個存儲過程立即將對象及其從事對象載入library cache中,并將他們都標記為保持(Keeping)狀態。對于這種對象,我們建議在實例啟動時就Keep住,以減少內存碎片的幾率。有一種觀點認為那些大對象(如包)是沒有必要被Keep住的,因為他們會被保持在共享池的保留區(如前所述,這個區通常使用率很低),所以一般不可能被清出。這個觀點是錯誤滴!因為大多數大對象實際上是被分為多個小的內存段被載入共享池的,因此根本不會因為對象的大小而受到特別的保護。另外,也不要通過頻繁調用某些對象以防止他們被從共享池中清出。如果共享池大小設置合理,在系統運行的高峰時期,LRU鏈表會相對較短,那些沒有被pin住的對象會很快被清出,除非他們被keep住了。
6、關于Shared Pool的重要參數(1) ?SHARED_POOL_SIZE它指定了Shared Pool的大小。9i下,在32位系統中,這個參數的默認值是8M,而64位系統中的默認值位64M。但是,在SGA中還存在一塊叫內部SGA消耗(Internal SGA Overhead)的內存被放置在共享池中。在9i及之前版本,共享池的統計大小(通過v$sgastat視圖統計)為SHARED_POOL_SIZE +內部SGA消耗大小。而10g以后,SHARED_POOL_SIZE就已經包含了這部分內存大小。因此在10g中,共享池的實際使用大小就是SHARED_POOL_SIZE -內部SGA消耗大小,這在配置共享池大小時需要考慮進去,否則,扶過SHARED_POOL_SIZE設置過小,在實例啟動時就會報ORA-00371錯誤。(2) SHARED_POOL_RESERVED_SIZE這個參數前面已經提到,指定了共享池中緩存大內存對象的保留區的大小。這里不再贅述。(3) ?_SHARED_POOL_RESERVED_MIN_ALLOC這個參數前面也已經介紹,設置了進入保留區的對象大小的閥值。
更多oracle視頻教程:http://crm2.qq.com/page/portalpage/wpa.php?uin=800060152&f=1&ty=1&aty=0&a=&from=6
4、保留共享池前面提到,如果Oracle解析一個 PL/SQL程序單元,也需要從共享池中分配內存給這些程序單元對象。由于這些對象本一般比較大(如包),所以分配的內存空間也相對較大。系統經過長時間運行后,共享池可能存在大量內存碎片,導致無法滿足對于大塊內存段的分配。為了使有足夠空間緩存大程序塊,Oracle專門從共享池內置出一塊區域來來分配內存保持這些大塊。這個保留共享池的默認大小是共享池的5%。它的大小也可以通過參數SHARED_POOL_RESERVED_SIZE來調整。保留區是從共享池中分配,不是直接從SGA中分配的,它是共享池的保留部分,用于存儲大塊段。Shared Pool中內存大于5000字節的大段就會被存放在共享池的保留部分。而這個大小限制是通過隱含參數_SHARED_POOL_RESERVED_MIN_ALLOC來設定的(如前面所說,隱含參數不要去修改它)。除了在實例啟動過程中,所有小于這個數的內存段永遠都不會放到保留部分中,而大于這個值的大內存段也永遠不會存放到非保留區中,即使共享池的空間不夠用的情況下也是如此。保留區的空閑內存也不會被包含在普通共享池的空閑列表中。它會維護一個單獨的空閑列表。保留池也不會在它的LRU列表中存放可重建(Recreatable關于內存段的各種狀態我們在后面的內容中再介紹)段。當釋放普通共享池空閑列表上的內存時是不會清除這些大段的,同樣,在釋放保留池的空閑列表上的大內存段時也不會清除普通共享池中內存。通過視圖V$SHARED_POOL_RESERVED可以查到保留池的統計信息。其中字段REQUEST_MISSES記錄了沒有立即從空閑列表中得到可用的大內存段請求次數。這個值要為0。因為保留區必須要有足夠個空閑內存來適應那些短期的內存請求,而無需將那些需要長期cache住的沒被pin住的可重建的段清除。否則就需要考慮增大SHARED_POOL_RESERVED_SIZE了。可以通過觀察視圖V$SHARED_POOL_RESERVED的MAX_USED_SPACE字段來判斷保留池的大小是否合適。大多數情況下,你會觀察到保留池是很少被使用的,也就是說5%的保留池空間可能有些浪費。但這需要經過長期觀察來決定是否需要調整保留池大小。保留區使用shared pool的LRU鏈表來管理內存塊,但是在做掃描時,相互是不受影響的。例如,內存管理器掃描shared pool的LRU鏈表,清出空間以分配給一個小于5000字節的內存請求,是不會清出保留區的內存塊的,相反亦然。5、將重要、常用對象保持(Keep)在共享池中根據LRU算法,一些一段時間沒有使用到的內存塊會被情況釋放。這就可能導致一些重要的對象(如一個含有大量通用算法函數的包、被cache的序列)被從內存中清除掉。這些對象可能只是間歇被使用,但是因為他們的處理過程復雜(不僅包本身重新分配內存、解析,還要檢查里面的所有語句),要在內存中重建他們的代價非常大。我們可以通過調用存儲過程DBMS_SHARED_POOL.KEEP將這些對象保持在共享池中來降低這種風險。這個存儲過程立即將對象及其從事對象載入library cache中,并將他們都標記為保持(Keeping)狀態。對于這種對象,我們建議在實例啟動時就Keep住,以減少內存碎片的幾率。有一種觀點認為那些大對象(如包)是沒有必要被Keep住的,因為他們會被保持在共享池的保留區(如前所述,這個區通常使用率很低),所以一般不可能被清出。這個觀點是錯誤滴!因為大多數大對象實際上是被分為多個小的內存段被載入共享池的,因此根本不會因為對象的大小而受到特別的保護。另外,也不要通過頻繁調用某些對象以防止他們被從共享池中清出。如果共享池大小設置合理,在系統運行的高峰時期,LRU鏈表會相對較短,那些沒有被pin住的對象會很快被清出,除非他們被keep住了。
6、關于Shared Pool的重要參數(1) ?SHARED_POOL_SIZE它指定了Shared Pool的大小。9i下,在32位系統中,這個參數的默認值是8M,而64位系統中的默認值位64M。但是,在SGA中還存在一塊叫內部SGA消耗(Internal SGA Overhead)的內存被放置在共享池中。在9i及之前版本,共享池的統計大小(通過v$sgastat視圖統計)為SHARED_POOL_SIZE +內部SGA消耗大小。而10g以后,SHARED_POOL_SIZE就已經包含了這部分內存大小。因此在10g中,共享池的實際使用大小就是SHARED_POOL_SIZE -內部SGA消耗大小,這在配置共享池大小時需要考慮進去,否則,扶過SHARED_POOL_SIZE設置過小,在實例啟動時就會報ORA-00371錯誤。(2) SHARED_POOL_RESERVED_SIZE這個參數前面已經提到,指定了共享池中緩存大內存對象的保留區的大小。這里不再贅述。(3) ?_SHARED_POOL_RESERVED_MIN_ALLOC這個參數前面也已經介紹,設置了進入保留區的對象大小的閥值。
更多oracle視頻教程:http://crm2.qq.com/page/portalpage/wpa.php?uin=800060152&f=1&ty=1&aty=0&a=&from=6
轉載于:https://blog.51cto.com/19880614/1175845
總結
以上是生活随笔為你收集整理的Oracle内存结构详解(三)--管理Oracle Share Pool的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: MVC Razor 语法(转)
- 下一篇: 有关CNN网络结构的总结