共享池shared pool的概念
用戶提交的命令:解析、執行
用戶命令的解析
解析的過程是一個相當復雜的過程,它要考慮各種可能的異常情況比如SQL語句涉及到的對象不存在、提交的用戶沒有權限等等而且還需要考慮如何執行SQL語句采用什么方式去獲職數據等解析的最終結果是要產生oracle自己內部的執行計划從而指導SQL的執行過程。可以看到,解析的過程是一個非常消耗資源的過程。因此oracle在解析用戶提交的SQL語句的過程中如果對每次出現的新的SQL語句,都按照標准過程完整的從頭到尾解析一遍的話效率太低尤其隨着並發用戶數量的增加、數據量的增加數據庫的整體性能將直線下降。
shared pool=Library cache+dictionay cache
Library cache是重點;所有信息都放在dictionary cache
數據獲取方式:全表/索引;表是如何連接;
代碼共享----執行計划共享
SQL語句靜態部分和動態部分:
oracle對SQL語句進行了概括和抽象將SQL語句提煉為兩部分一部分是SQL語句的靜態部分也就是SQL語句本身的關鍵詞、所涉及的表名稱以及表的列等另一部分就是SQL語句的動態部分.也就是SQL語句中的值(即表里的數據)很明顯的,整個數據庫中所包含的對象數量是有限的,而其中所包含的數據則是無限的,而正是這無限的數據導致了SQL語句的千變萬化,也就是說在數據庫運行的過程中發生的所有SQL語句中靜態部分可以認為是有限的.而動態部分則是無限的。而實際上.動態部分對解析的影響相比靜態部分對解析的影響來說是微乎其微.也就是說通常情況下對於相同的靜態部分的SQL語句來說不同的動態部分所產生的解析結果(執行計划)基本都是一樣的這也就為oracle提高解析SQL語句的效率提供了方向
Select····From····靜態Where····動態
——————通過參數解決動態沒有綁定變量的問題
共享池
oracle會將用戶提交來的SQL語句都緩存在內存中。每次處理新的一條SQL語句時都會先在內存中查看是否有相同的SQL語句如果相同則可以減少最重要的解析工作〔也就是生成執行計划)從而節省了大量的資源:反之如果沒有找到相同的SQL語句,則必須重新從頭到尾進行完整的解析過程這部分存放SQL語句的內存就叫做共享池( shared pool)當然shared pool里不僅僅是SQL語句,還包括管理shared pool的內存結構以及執行計划、控制信息等等內存結構,oracle通過內存結構管理
綁定變量
當orocle在shared pool中查找相同的SQL語句的過程中如果SQL語句使用了綁定變量( bind variable ) ,那么就是比較SQL語句的靜態部分。前面我們已經知道.靜態部分是有限的,很容易就能夠緩存在內存里從而找到相同的SQL語句的概率很高如果沒有使用綁定變量.則就是比較SQL語句的靜態部分和動態部分,而動態部分的變化是無限的.因此這樣的SQL語句很難被緩存在shared pool里畢竟內存是有限的.不可能把所有的動態部分都緩存在shared pool里,即使能夠緩存,管理這樣一個無限大的shared pool也是不可能完成的任務。不使用綁定變量導致的直接結果就是,找到相同的SQL語句的概率很低.導致必須完整的解析SQL語句,也就導致消耗更多的資源。從這里也可以看出,只有我們使用了綁定變量才真正遵循了oracle引入shared pool的哲學思想,才能更有效的利用shared pool
共享池=庫緩存+數據字典緩存
shared pool的大小由初始化參故shared_pool_size決定。10g以后可以不用設定該參數而只需要指定sga_target從而oracle將自動決定shared pool的大小尺寸,在一個很高的層次上來看.shared pool可以分為庫緩存(library cache )和數據字典緩存(dictionarycache )Library cache存放了最近執行的SQL語句、存儲過程、函數、解析樹以及執行計划等而dictionary cache則存放了在執行SQL語句過程中,所參照的數據宇典的信息包活SQL語句所涉及的表名、表的列、權限信息等dictionary cache也叫做row cache,因為這里面的信息都是以數據行的形式存放的.而不是以數據塊的形式存放的。對於dictionarycache來說oracle傾向於將它們一直緩存在shared pool里不會將它們交出內存.因此我們不用對它們進行過多的關注而librarycache則是shared pool里最重要的部分也是
在shared pool中進進出出最活躍的部分,需要我們仔細研究。所以我們在說到sharedpool實際上就可以認為是在指library caches
shared pool的內存結構(邏輯結構)
從一個邏輯層面來看shared pool由library cache和dictionary cache組成shared pool中組件之間的關系可以用下圖一來表示。從下面這個圖中可以看到當SQL語句(select objectid,objectname from sharedpool_test)進人library cache時,oracle會到dictionary cache中去找與sharedpool_test表有關的數據宇典信息比如表名、表的列等以及用戶權限等信息如果發現dictionary cache中沒有這些信息.則會將system表空間里的數據字典信息調入buffer cache內存.讀取內存數據塊里的數據字典內容,然后將這些讀取出來的數據字典內容按照行的形式放入dictionary cache里,從而構造出dc_tables之類的對象然后,再從dictionary cache中的行數據中取出有關的列信息放入library cache中。
圖:
shared pool結構(物理結構)
從一個物理的層面來看shared pool是由許多內存塊組成這些內存塊通常稱為chunks,Chunk是shared pool中內存分配的最小單位一個chunk中的所有內存都是連續的,這些chunk可以分為四類。這四類可以從x$ksmsp(該視圖中的每個行都表示shared pool里的
一個chunk)的ksmchcls字段看到:
SQL> select distinct(ksmchcls) from x$ksmsp:
recr
freeabl
R-freea
perm
no acce
R-free
free
已選擇7行.
1) free
這種類型的chunk不包含有效的對象.可以不受限制的被分配
2)recr
意味着recreatable,這種類型的chunks里包含的對象可以在需要的時候被臨時移走,
並且在需要的時候重新創建。比如對干很多有關共享SQL語句的chunks就是recreatable的
3)freeabl:這種類型的chunks包含的對象都是曾經被肥session使用過的.並且隨后會被完全或部分釋放的。這種類型的chunks不能臨時從內存移走因為它們是在處理過程中問產生的如果移走的話就無法被重建
4) perm
意味着permanent 這種類型的chunk.包含永久的對象,大型的permanent類型的chunks也可能含有可用空間,這部分可用空間可以在需要的時候釋放回shared pool里.
*****
Freeabl與會話有關如果移出無法重建
一堆的trunk
有多少個trunk就有多少個行
Ora-4013分配trunc時沒有找到trunc
rerc清空不是移走,然后快速重建,因為有一部分信息已經存在
當chunk屬於free類型的時候它既不屬於library caehe也不屬於dictionary caches如果該chunk被用於存放SQL游標時則該chunk進入librarycache,同樣如果該chunk被用於存放數據字典的信息時.則該chunk進入dictionary eache
在shared pool里可用的chunk(free類型)會被串起來成為可用鏈表(free lists ),也可以叫做buckets(一個可用璉表也就是一個bucket)
我們可以使用下面的命令將.shared pool的內容轉儲出來看看這些bucket
alter seeeion set events'immediate trace name heapdump level 2';
然后打開產生的轉儲文件.找到“FREE LIST部分可以發現類似如下圖所示的內容
SQL>alter session set events 'immediate trace name heppdump level 2';
會話已更改
FREE LISTS
Bucket 0 size=16
Ruckrt l size=20
Bucket 2 size=24
Bucket 3 size=28
Bucket 4 size=32
Bucket 5 size=36
Bucket 6 size=40
Rocket 7 size=44
················
Bucket 10 size=56
Bucket 11 size=60
Bucket 12 size=64
Bucket 13 size=68
Chunk6c3fffbcsz= 68 free " "
Bucket 14 size=72
Rueket IS size=75
每個bucket上掛的chunk的尺寸是不一樣的,有一個遞增的趨勢。我們可以看到,每個bucket都有一個size字段‘這個size就說明了該bucket上所能鏈接的可用chunk的大小尺寸
****
如果出現很多小的trunc
1檢查有沒有bug,造成shared pool問題
2為什么會出現小的trunc ,因為在反復的不停的分配trunc ,代碼沒有共享
當一個進程需要shared pool里的一個chunk時.假設當前需要21個單位的空間則該進程首先到符合所需空間大小的bucket(這里就是bucket 2)上去掃描以找到一個尺寸最合適的chunk掃描持續到bucket的最末端.直到找到完全符合尺寸的chunk為止.如早找列的chunk的尺寸比需要的尺寸要大則該chunk就會被拆分成兩個chunk,一個chunk被用來存放數據,而另外一個則成為free類型的chunk並被掛到當前該bucket上也就是bucket 2上然而,如果該bucket上不含有任何需要尺寸的chunk那么就從下一個非空的bucket上(這里就是bucket 3)獲得一個最小的chunk,如果在剩下的所有bucket上都找到可用的chunk ,則需要掃描已經使用的recreatable類型的chunk鏈表從該鏈表上釋放一部分的chunk出來因為只有receatable類型的chunk才是可以被臨時移出內存的.
當某個chunk正在被使用時(可能是用戶正在使用,也可能是使用了dbms_shared_pool包將對象釘在shared pool里),該chunk是不能被移出內存的比如某個SQL語句正在執行,那么該SQL語句所對應的游標對象是不能被移出內存的,該SQL語句所引用的表、索引等對象所占用的chunk也是不能被移出內存的。當sharedpool中無法找到足夠大小的所需內存時報ORA-4031錯誤。當出現4031錯的時候你查詢v$sgastat里可用的shared pool空間時可能會發現name為"free memory"的可用內存還足夠大.但是為何還是會報4031錯呢?事實上,在oracle發出4031錯之前.已經釋放了不少recreatable類型的chunk了,因此會產生不少可用內存但是這些可用chunk中.沒有一個chunk是能夠以連續的物理內存提供所需要的內存空問的從而才會發出4031的錯
SQL> select * from v$sgastat where name=‘free memory’;
POOL NAME BYTES
shared pool free memory 7119640
large pool free memory 3988096
java pool free memory 4190304
****
l.share pool中的trunc是釘住的
2.sql-) share pool中行成行標很多的trunc會掛在一起
對bucket的掃描,管理、分配chunk等這些操作都是在shared pool lateh的保護下進行的。如果shared pool含有數量巨大的非常小的free類型的chunk的話.則掃描bucket時shared pool latch會被鎖定很長的時間,這也是8i以前的shared pool later爭用的主要原因而如果增加shared pool尺寸的話.僅僅是延緩shared pool latch的爭用,而到最后,就會因為小的free chunks的越來越多,爭用也越來越嚴重,而到了9i以后由於大大增加了可用chunk鏈表(也就是bucket)的數量.同時每個bucket所管理的可用chunk的尺寸遞增的幅度非常小,於是就可以有效的將可用的chunk都均勻的分布在所有的bucket上,這樣的結果就是每個bucket上所掛的free類型的chunk都不多.所以在查找可用chunk而持有shared pool latch的時間也可以縮短很多
**************
Free類型trunc
9i bucket增多,trunc就小了
1個lath管理多個bucket
1個cpu有一個latch
引起latch爭用的原困是分配trunc時出的問題:1trunc太長,latch是串行的,讀寫都要先獲取,即使是讀,另一個進程獲取latch只能等,一直等到時間片結束。lock是並行的,可以是同時讀。大量分配trunc是連鎖問題,加大bucket使trunc減小,latch增多,手工增加latch數量解決latch不夠的問題****
對於非常大的對象oracle會為它們單獨從保留區域里分配空間.而不是從這個可用chunk鏈表中來分配空問。這部分空間的大小尺寸就是由初始化參數shared_pool_reserved_size決定的缺省為shared_pool_size的5%,這塊保留區域與正常的chunk的管理是完全分開的,小的chunk不會進入這塊保留區域.而這塊保留區域的可用chunk也不會掛在bucket上,這塊保留區域的使用情況可以從視圖v$shared_pool_reserved中看到。通常來說該視圖的requestmisses字段顯示了需要從保留區域的可用鏈表上上獲得大的chunk而不能獲得的次數該字段應該盡量為0。
SQL> show parameter shared_pool_reserved;
NAME TYPE VALUE
shared_pool_reserved_size biginteger 3774873
SQL, select repuests,repuest_misses from V$shared_pool_reserved;
REQUESTS REQUEST_MISSES
37 3
library cache最主要的功能就是存放用戶提交的SQL語句、SQL語句相關的解析樹〔解析樹也就是對SQL語句中所涉及到的所有對象的展現)、執行計划、用戶提交的PLSQL程序塊〔包括匿名程序塊、存儲過程、包、函數等)以及它們轉換后能夠被orade執行的代碼等,為了對這些內存結構進行管理還存放了很多控制結構包括lock, pin, dependency table等
library cache還存放了很多的數據庫對象的信息,包括表、索引等等有關這些數據庫對象的信息都是從dictionary cache中獲得的。如果用戶對library cache中的對象信息進行了修改,則這些修改會返回到dictionary cache中。
********
Sql文本解析樹.執行計划
Sql涉及的對象信息〔不能每次都訪問字典)
在library cache中存放的所有的信息單元都叫做對象〔object這些對象可以分成兩類,一類叫存儲對象,也就是上面所說的數據庫對象,它們是通過顯式的SQL語句或PL/SQL程序創建出來的,如果要刪除它們.也必須通過顯示的SQL命令進行刪除此類對象包活表、視圖、索引、包、函數等等;另一類叫做過渡對象池就是上面所說的用戶提交的SQL語句或者提交的PL/SQL程序塊等;這些過渡塊在執行SQL語句或PL/SQL程序的過程中產生的,並緩存在內存里。如果實例關閉則刪除.或者由於內存不足而被交換出去從而被刪除
Sql和執行計划是過度對象,表的信息是存儲對象
父子游標
當用戶提交SQL語句或PLSQL程序塊到oracle的shared pool以后,在library cache中生成的一個可執行的對象,這個對象就叫做游標(cusor),不要把這里的游標與標准SQL(ANSI SQL)的游標混淆起來了,標准SQL的游標是指返回多條記錄的SQL形式.需要定義、打開、關閉。下面所說到的游標如無特別說明都是指library cache中的可執行的對象。游標是可以被所有進程共享的也就是說如果100個進程都執行相同的SQL語句.那么這100個進程都可以同時使用該SQL語句所產生的游標從而節省了內存。每個游標都是由library cache中的兩個或多個對象所體現的至少兩個對象,一個對象叫做父游標(parentcursor),包含游標的名稱以及其他獨立於提交用戶的信息。從v$sqlarea視圖里看到的都是有關父游標的信息;另外一個或多個對象叫做子游標〔child cursors ) ,如果SQL文本相同但是可能提交SQL語句的用戶不同,或者用戶提交的SQL語句所涉及到的對象為同名詞等,都有可能生成不同的子游標,因為這些SQL語句的文本雖然完全一樣.但是上下文環境卻不一樣因此這樣的SQL語句不是一個可執行的對象必須細化為多個子游標后才能夠執行,子游標含有執行計划或者PL/SQL對象的程序代碼塊等;
*******
執行對象:sql+執行計划十相關信息
游標是共享的
父游標:sql文本
子游標:具體的信息.子游標比父游標大
HASH算法
在介紹library cache的內部管理機制前先簡單介紹一下所謂的hash算法
oracle內部在實現管理的過程中大量用到了hash算法。hash算法是為了能夠進行快速查找定位所使用一種枝術所謂hash算法,就是根據要查找的值.對該值進行一定的hash算法后得出該值所在的索引號.然后進進入到該值應該存在的一列數值列表(可以理解為一個二維數組)里通過該索引號去找它應該屬於哪一個列表然后再進人所確定的列表里對其中所含有的值進行一個一個的比較從而找到該值這樣就避免了對整個數值列表進行掃描才能找到該值。這種全掃描的方式顯然要比hash查找方式低效很多,其中每個索引號對應的數值列在oracle里都叫做一個hash bucket。
我們來列舉一個最簡單的hash算法.假設我們的數值列表最多可以有10個元素也就是有10個hash buckets ,每個元素最多可以包含20個數值。對應的二維數組就是t[10][20]我們可以定義hash算法為n MOD10通過這種算法可以將所有進入的數據均勻放在10個hash bucket里面hash bucket,編號從0到9,比如我們把1到100都通過這個hash函數均勻放到這10個hash bucket里,當查找32在哪里時只要將32 MOD 10等於2這樣就知道可以到2號hash bucket里去找也就是到t[2][20]里去找2號hash bucket里有10個數值逐個比較2號hash bucket里是否存在32就可以了
library cache就是便用多個hash bucket來管理的‘其hash算法當然比我們前面列舉的要復雜多了。每個hash bucket后面都串連着多個句柄〔該句柄叫做library cache object
handle ),這些句柄描述了library cache里的對象的一些屬性包括名稱、標記、指向對象所
處的內存地址的指針等。可以用下圖來描述librarycaphe的整體結構
指針:指向文件結構的指針
Heap堆
Name:sql文件信息
Name space .名稱空間
Look owner誰持有這個鎖
Dependency table依賴表
Heap指向另外一些對象鏈表
圖:
當一條SQL語句進入library cache的時候,先將SQL文本轉化為對應ASCII數值然后對該這些ASCII數值進行hash函數的運算,傳入函數的是SQL語句的名稱( name對於
SQL語句來說其name就是SQL語句的文本)以及命名空間(namespace ,對於SQL語句來說是"SQL AREA",表示共享游標。可以從視圖v$libarycache里找到所有的namespace)運用hash函數后得到一個值該值就是hash bucket的號碼,從而該SQL語句被分配到該號的hash bucket里去,實際上.hash bucket就是通過串聯起來的對象句柄才體現出來的.它本身是一個邏輯上的概念.是一個邏輯組,而不像對象是一個具體的實體。oracle根
據sharedpool_size所指定的shared pool尺寸自動計算hash buckets的個數.sharedpool越大則可以掛載的對象句柄就越多
SQL>select distinct(namespace) from v$librarycache;
NAMESPACE
BODY
JAVA DATA
SQL AREA
OBJECT
PIPE
JAVA RESOURCE
TABLE/PROCEDURE
TRIGGER
INDEX
JAVA SOURCE
CLUSTER
己選擇11行
當某個進程需要處理某個對象時比如處理一條新進人的SQL語句時它會對該SQL語句應用hash函數算法以決定其所在的hash bucket的編號然后進入該hash bucket進行掃描並比較有可能會發生該對象的句柄存在但是句柄所指向的對象已經被交換出內存的情況出現,這時對應的對象必須被再次裝載(reload)也可能該對象的句柄都不存在這時進程必須重新構建一個對象句柄掛到hash bucket上然后再重新裝載對象SQL語句相關的對象有很多(最直觀的就是SQL語句的文本),這些對象都存放在library cache里它們都通過句柄來訪問可以把library cache理解為一本書.而SQL語句的對象就是書中的頁.而句柄就是目錄.通過目錄可以快速定位911指定內容的頁對象,句柄存放了對象的名稱(name ),對象所屬的命名空間(namespace),有關對象的一些標記(比如對象是否為只讀、為本地對象還是遠程對象、是否被pin在內存中等等)以及有關對象的一些統計信息等,而且,對象句柄中還存放了當前正在lock住和pin住該對象的用戶列表、以及當前正在等待lock和pin該對象的用戶列表,對象句柄中存放的最重要的內容就是指向Heap 0對象的指針了。Heap 0用來存放與對象有直接關系的一些信息.比如對象類型、對象相關的表(比如依賴表、子表等)、指向對象的其他數據塊的指針(這些數據塊指向了實際存放SQL文本、PVSQL代碼、錯誤信息等的大內存塊,這些大內存塊依次叫做Heap
1, 2, 3, 4等)等信息。
圖