關于oracle記憶體管理這一章,還是非常重要滴,不過嫩說白了就三個東西,PGA,UGA,SGA...
pga不多說啦,現在一般是自動管理的,主要再看看sga吧:在指令行裡輸入show sga,會出現如下幾個參數:
fixed size:也叫fixes_sga固定的sga,包括了一些資料庫與執行個體的控制資訊、狀态資訊、字典資訊等,這塊區域打資料庫啟動的時候就在sga中,而且永遠不會改變。
variable size:包含了share pool,large pool,java pool,stream pool,遊标區和其他結構。
database buffers:在v$sgastat視圖中叫buffer_catch。有時候也叫data buffer,說白了就是資料庫緩沖區,
redo buffers:在v$sgastat視圖中叫 log_buffer.為日志寫程序提供的一個緩沖區,因為在一般的OLTP系統中送出很頻繁,是以一般不大。其大小有log_buffer參數控制其大小取512k和 (128*cpu個數)k 較大者。
data buffer catch:裡面有三個池,在8i以前隻有一個預設池,但是以後的版本增加了保持池和回收池。
預設池(由db_catch_size參數決定其大小):一直就有的那個,所有的段塊一般都在這個池中,通路最頻繁的池。
保持池(db_keep_catch_size):通路相對比較頻繁的段塊就會被放在這裡面,這樣就防止了放在預設池中出現老化的情況。
回收池(db_recycle_catch_size):通路很随即,很少的大段一般放在這裡,随時可能重新整理輸出到磁盤,也有可能随時調入進來,這樣效率就相對于預設池和保持池的低一點。一般這個池很小,可以讓塊更快的進出,友善管理。
這樣會增加DBA 所要執行的管理工作,因為要考慮3 個緩存,要确定它們的大小,還要為這些緩存配置設定對象。還要記住,這些池之間沒有共享,是以,如果保持池有大量未用的空間,即使預設池或回收池空間不夠用了, 保持池也不會把未用空間交出來。總之,這些池一般被視為一種非常精細的低級調優裝置,隻有所有其他調優手段大多用過之後才應考慮使用(如果可以重寫查詢, 将I/O 減少為原來的1/10,而不是建立多個緩沖區池,我肯定會選擇前者!)。
從Oracle9i 開始,除了預設池、保持池和回收池外,DBA 還要考慮第4 種可選的緩存:db_Nk_caches。增加這些緩存是為了支援資料庫中多種不同的塊大小。在Oracle9i 之前,資料庫中隻有一種塊大小(一般是2 KB、4 KB、8 KB、16 KB 或32 KB)。從Oracle9i 開始,資料庫可以有一個預設的塊大小,也就是預設池、保持池或回收池中存儲的塊的大小,還可以有最多4 種非預設的塊大小,與原來預設池中的塊一樣,這些緩沖區緩存中的塊會以同樣的方式管理,沒有針對不同的池采用任何特殊的算法。
data buffer catch 中的塊管理:
在各個池中的管理算法是一樣的,我們就以一個預設池(可能有多個預設池)為例,講述oracle如何管理資料塊緩存中的資料塊,額,這些塊的管理實際上就是位置上的管理,在每個池中都會有兩個重要的清單來管理這些塊,其中一個清單就是 髒塊清單,其中的塊在那排着隊等待着DBWn 程序将其依次寫入磁盤。另一個清單是一個接觸計數的表,oracle給每個塊加一個接觸計數,如果通路這個塊的次數多,大約3秒鐘這個計數就會加1,但是過一會oracle會自動給你冷卻這個塊,把這個數再往下減。。塊可以在這兩種清單中邏輯的移動,記住不是實體的移動。。隻改變指針我估計。。
現在,由于我還沒有配置一個16 KB 的緩存,是以無法建立這樣一個表空間。要解決這個問題,可以在以下方法中選擇一種。我可以設定DB_16K_CACHE_SIZE 參數,并重新開機資料庫。也可以縮小另外的某個SGA元件,進而在現有的SGA 中騰出空間來建立一個16 KB 的緩存。或者,如果SGA_MAX_SIZE 參數大于目前的SGA 大小,我還可以直接配置設定一個16 KB 的緩存。
注意從Oracle9i 開始,即使資料庫已經啟動并且正在運作,你也能重新設定各個SGA 元件的大小。如果你想擁有這個能力,能夠“擴大”SGA 的大小(超過初始配置設定的大小),就必須把SGA_MAX_SIZE參數設定為大于已配置設定SGA 的某個值。例如,如果啟動之後,你的SGA 大小為128 MB,你想再為緩沖區緩存增加另外的64 MB,就必須把SGA_MAX_SIZE 設定為192 MB 或更大,以便擴充。
在這個例子中,我采用收縮的辦法,即縮小我的DB_CACHE_SIZE,因為目前這個參數設定得太大了:
ops$tkyte@ORA10G> show parameter db_cache_size
NAME TYPE VALUE
------------------ ----------- ----------------------
db_cache_size big integer 1G
ops$tkyte@ORA10G> alter system set db_cache_size = 768m;
System altered.
ops$tkyte@ORA10G> alter system set db_16k_cache_size = 256m;
ops$tkyte@ORA10G> create tablespace ts_16k
datafile size 5m blocksize 16k;
Tablespace created.
這樣一來,我就建立了另外一個緩沖區緩存,要用來緩存16 KB 大小的塊。預設池(由db_cache_size參數控制)大小為768 MB,16 KB 緩存(由db_16k_cache_size 參數控制)大小為256 MB。這兩個緩存是互斥的,如果一個“填滿”了,也無法使用另一個緩存中的空間。這樣DBA 就能很精細地控制記憶體的使用,但是這也是有代價的。代價之一就是複雜性和管理。使用多個塊大小的目的并不是為了性能或作為一個調優特性,而是為了支援可傳輸的表空間,也就是可以把格式化的資料檔案從一個資料庫傳輸或附加到另一個資料庫。比如說,通過實作多個塊大小,可以取得一個使用8
KB 塊大小的事務系統中的資料檔案,并将此資訊傳輸到使用16 KB 或32 KB 塊大小的資料倉庫。不過,對于測試來說,有多個塊大小很有好處。如果你想看看你的資料庫如何處理另一個塊大小,例如,如果使用4 KB 的塊而不是8 KB 的塊,一個表會占用多大的空間。現在由于可以支援多個塊大小,你就能很輕松地進行測試,而不必建立一個全新的資料庫執行個體。還可以把多個塊大小用作一種精細調優工具,對一組特定的段進行調優,也就是為這些段配置設定各自的私有緩沖區池。
資料庫讀取資料的最小機關是oracle資料塊。還有一個問題就是oracle中有很多的”讀“ 什麼實體讀,邏輯讀之類的,目前我知道的記憶體内的叫邏輯讀,讀磁盤的叫實體讀,以後再随時補充吧。
還有一個問題就是哪個程序将資料檔案讀到了buffer catch?
oracle裡面有一些最繁忙的程序叫server process 程序,每一個使用者連接配接到oracle資料庫伺服器的時候(一個session建立),oracle在背景會給每一個使用者起一個server process程序,當這個使用者的一條sql語句發過來,就隻這一個server process程序拿着這個語句去shared pool裡面做的解析,生成執行計劃,然後再由他去資料檔案裡把需要的塊讀入buffer
catch中,再由他把執行結果傳回給使用者。。。既然server process做這麼多得工作,那肯定也需要一定的記憶體(工作室)來處理資料,恩,這就是PGA了,PGA就是這個前台程序和背景程序的記憶體區,當然背景程序用的比較少。
視圖v$db_catch_advice由oracle自動根據一些資料模型算法,收集資訊後産生一系列的值,作為調整data buffer 的參考。
shared pool:關注這麼幾個問題:
1、一條語句進來後如何找是否已經被解析過?
2、如何生成這個sql語句的執行計劃的問題?
3、如何在shared pool中找到空閑的空間存儲執行計劃?
4、為了解析這個sql語句,肯定需要通路資料字典,資料字典在哪呢,在system表空間中,對應的實體檔案就是system01.dbf檔案。這就需要從這個檔案上将資料字典塊讀到data buffer catch中,然後shared pool 從資料緩沖區中抽取需要的資料?
一個sql語句解析(花費老多cpu的時間),将解析好的語句和生成的執行計劃都會放在shared pool中。是以可以認為shared pool中有兩類資訊,一類就是前面說的編譯好的sql語句和執行計劃,另一類就是資料字典緩沖區(data dictionary catch)的資料字典資訊。
共享池的特點是有大量小的記憶體塊(chunk),一般為4 KB 或更小。要記住,4 KB 并不是一個硬性限制,可能有的記憶體配置設定會超過這個大小,但是一般來講,我們的目标是使用小塊的記憶體來避免碎片問題。如果配置設定的記憶體塊大小顯著不同(有的很小,有的卻相當大),就可能出現碎片問題。共享池中的記憶體根據LRU(最近最少使用)的原則來管理。在這方面,它類似于緩沖區緩存,如果你不用某個對象,它就會丢掉。為此提供了一個包,名叫DBMS_SHARED_POOL,這個包可用于改變這種行為,強制性地“釘住”共享池中的對象。可以使用這個過程在資料庫啟動時加載頻繁使用的過程和包,并使它們不至于老化。不過,通常如果過一段時間共享池中的一段記憶體沒有得到重用,它就會老化。甚至PL/SQL
代碼(可能相當大)也以一種分頁機制來管理,這樣當你執行一個非常大的包中的代碼時,隻有所需的代碼會加載到共享池的小塊中。如果你很長時間都沒有用它,而且共享池已經填滿,需要為其他對象留出空間,它就會老化。
設計共享池是為了反複使用查詢計劃。如果每個查詢都是全新的,都是以前從來沒有見過的查詢,那麼緩存隻會增加開銷。共享池反而會損害性能。為了解決這個問題,很多人都會用一種看似合理的常用技術,也就是向共享池增加更多的空間,但是這種做法一般隻會使問題變得比以前更糟糕。由于共享池不可避免地會再次填滿,比起原來較小的共享池來說,開銷甚至更大,原因很簡單,與管理一個較小的滿共享池相比,管理一個大的滿共享池需要做更多的工作。對于這個問題,真正的解決方案隻有一個,這就是使用共享SQL,也就是重用查詢。在前面(第1
章),我們簡要介紹了參數CURSOR_SHARING,在這方面,遊标共享可以作為一種短期的解決方案。不過,真正要解決這個問題,首當其沖地還是要使用可重用的SQL。即使在最大的系統上,我發現一般也最多有10 000~20 000 條不同的SQL 語句。大多數系統隻執行數百個不同的查詢。
對于間歇性通路的比較大的對象,例如自定義的過程與包,如果在運作過程中不想被系統調換出去,可以采用DBMS_SHARED_POOL.KEEP這個存儲過程将該過程或者包pin在共享池中。
我們可以用一下指令手工清除共享池的内容:
alter system flush shared pool;
在oracle9i之前的版本中共享池的sum(bytes)結果與shared_pool_size是沒有關系的,但是10g以後中這兩個值變得相等了,可以分别查詢之:
select sum(bytes) from v$sgastat where pool='shared pool';
show parameter shared_pool_size;
big pool:之是以叫大池,是因為這個池是用來做大塊記憶體的配置設定(要知道shared pool不能做大塊記憶體的處理),共享池是采用LRU清單管理的,這種管理方式對于緩存或者重複使用資料塊很合适,但是,對于大池,一般都是配置設定一塊大的記憶體用來給UGA使用,當一個使用者的session斷了之後,此塊記憶體就會直接收回,這樣用LRU算法并不合适;
在共享池中,實際上沒有釋放記憶體塊的概念。你隻是配置設定記憶體,然後使用,再停止使用而已。過一段時間,如果需要重用那個記憶體,Oracle 會讓你的記憶體塊老化。如果隻使用共享池,問題在于:一種大小不一定全局适用。
大池主要用于如下三個方面:
1)共享伺服器連接配接方式中,在SGA中配置設定UGA區,就在大池中配置設定。
2)在并行查詢中,允許大池配置設定程序間的消息緩沖區,這些緩沖區用于協調并行查詢伺服器。
3)rman備份中用于磁盤的 I/O 緩沖區。
data dictionary:資料庫裡有兩類資訊,一類就是資料字典資訊,包括這個資料庫内有多少表,多少索引,每個表有多少列,每個列的名字等等等,詳細資訊,都以表的形式存儲在system表空間中;另一類就是生産資料啦。