官术网_书友最值得收藏!

1.2 實(shí)例的內(nèi)存結(jié)構(gòu)

當(dāng)實(shí)例啟動(dòng)時(shí),系統(tǒng)為實(shí)例分配了一段內(nèi)存空間,并啟動(dòng)若干后臺(tái)進(jìn)程。內(nèi)存空間分成不同的部分,分別用來存儲(chǔ)不同的信息。具體來說,在這段內(nèi)存空間中存儲(chǔ)以下信息:

●程序代碼:Oracle的可執(zhí)行代碼;

●緩沖數(shù)據(jù):用戶要訪問的數(shù)據(jù)、重做日志等。這部分內(nèi)存叫作SGA;

●與會(huì)話有關(guān)的信息;

●與進(jìn)程間通信有關(guān)的信息,如加鎖的信息。

在上述內(nèi)存區(qū)域中,最重要的是SGA。SGA是由多個(gè)緩存和緩沖池組成的,在這些內(nèi)存結(jié)構(gòu)中存儲(chǔ)不同類型的數(shù)據(jù)。根據(jù)存儲(chǔ)數(shù)據(jù)的類型,SGA中主要包含以下類型的內(nèi)存結(jié)構(gòu):

●數(shù)據(jù)庫(kù)高速緩存;

●重做日志緩沖區(qū);

●共享池;

●Java池;

●大池。

其中,數(shù)據(jù)庫(kù)高速緩存由許多緩沖區(qū)組成,共享池由數(shù)據(jù)字典緩存和庫(kù)緩存兩部分組成。在這里之所以使用了緩存和緩沖區(qū)兩個(gè)概念,是因?yàn)樗鼈儊碜圆煌挠⑽膯卧~,緩存是從單詞cache翻譯過來的,而緩沖區(qū)來自單詞buffer。

當(dāng)實(shí)例運(yùn)行時(shí),可以通過命令查看SGA的大小。SGA由不同的內(nèi)存結(jié)構(gòu)組成,所以查看的結(jié)果是分別列出了不同組成部分的大小。例如,在SQL*Plus中執(zhí)行SHOW命令可以查看當(dāng)前SGA的大小,如圖1-3所示。

圖1-3

SGA更詳細(xì)的信息可以從動(dòng)態(tài)性能視圖v$sga、v$sgainfo、v$sgastat中獲得。從這些視圖中可以獲得每種緩沖區(qū)和緩存的大小信息。

下面開始介紹實(shí)例內(nèi)存結(jié)構(gòu)的“數(shù)據(jù)庫(kù)高速緩存”“重做日志緩沖區(qū)”“共享池”“Java池”及“PGA(程序全局區(qū))”。

1.2.1 數(shù)據(jù)庫(kù)高速緩存

數(shù)據(jù)庫(kù)高速緩存是SGA中的一段存儲(chǔ)區(qū)域,用來存放用戶最近訪問的數(shù)據(jù)。當(dāng)用戶訪問數(shù)據(jù)文件中的數(shù)據(jù)時(shí),服務(wù)器進(jìn)程首先查看這樣的數(shù)據(jù)是否已經(jīng)存在于數(shù)據(jù)庫(kù)高速緩存中。如果是,則直接在數(shù)據(jù)庫(kù)高速緩存對(duì)數(shù)據(jù)進(jìn)行訪問,并將處理結(jié)果返回給用戶,這次數(shù)據(jù)訪問叫作“命中”,這樣的讀操作稱為“邏輯讀(Logical Reads)”。否則,服務(wù)器進(jìn)程將數(shù)據(jù)從數(shù)據(jù)文件的數(shù)據(jù)塊中讀到數(shù)據(jù)庫(kù)高速緩存中,然后在數(shù)據(jù)庫(kù)高速緩存對(duì)數(shù)據(jù)進(jìn)行訪問,這次數(shù)據(jù)訪問叫作“未命中”,這樣的讀操作稱為“物理讀(Physical Reads)”。顯然,如果直接在數(shù)據(jù)庫(kù)高速緩存訪問數(shù)據(jù),要比從數(shù)據(jù)文件中讀數(shù)據(jù)快得多。所以,訪問數(shù)據(jù)的命中率越高,數(shù)據(jù)庫(kù)的性能就越高。對(duì)數(shù)據(jù)庫(kù)進(jìn)行性能優(yōu)化的一個(gè)重要方面就是提高邏輯讀在所有讀操作中所占的比例。

數(shù)據(jù)庫(kù)高速緩存的大小通過初始化參數(shù)DB_CACHE_SIZE來指定。提高數(shù)據(jù)訪問命中率最直接的方法是增加數(shù)據(jù)庫(kù)高速緩存的大小,但它的大小不能無限制地增加,它要受到物理內(nèi)存大小的限制。

用戶訪問的數(shù)據(jù)都存儲(chǔ)在數(shù)據(jù)文件中,數(shù)據(jù)文件被劃分為許多大小相同的數(shù)據(jù)塊。數(shù)據(jù)塊是Oracle進(jìn)行讀/寫的基本單位,也就是說,即使用戶只希望訪問一個(gè)字節(jié)的數(shù)據(jù),那么數(shù)據(jù)所在的整個(gè)數(shù)據(jù)塊也將被讀到數(shù)據(jù)高速緩存中。同樣,在寫數(shù)據(jù)時(shí),也是以數(shù)據(jù)塊為單位的。這樣做的好處是提高了數(shù)據(jù)庫(kù)服務(wù)器的吞吐量。

數(shù)據(jù)庫(kù)高速緩存是由一個(gè)個(gè)的緩沖區(qū)組成的,數(shù)據(jù)從數(shù)據(jù)文件中被讀到數(shù)據(jù)庫(kù)高速緩存中之后,就放在這些緩沖區(qū)中。緩沖區(qū)的大小與數(shù)據(jù)塊的大小一致,一個(gè)數(shù)據(jù)塊的內(nèi)容恰好放在一個(gè)緩沖區(qū)中。數(shù)據(jù)塊的大小由初始化參數(shù)db_block_size指定,并且在數(shù)據(jù)庫(kù)創(chuàng)建后不能被修改,那么緩沖區(qū)的大小也由這個(gè)參數(shù)決定。所有緩沖區(qū)大小的總和由初始化參數(shù)DB_CACHE_SIZE指定。假設(shè)在參數(shù)文件中定義了以下兩個(gè)初始化參數(shù):

●DB_BLOCK_SIZE=8192

●DB_CACHE_SIZE=25165824

這說明每個(gè)緩沖區(qū)的大小為8192字節(jié),即8KB,而所有緩沖區(qū)總的大小為25165824字節(jié),即24MB,這也是整個(gè)數(shù)據(jù)庫(kù)高速緩存的大小。由此可以計(jì)算組成整個(gè)數(shù)據(jù)庫(kù)高速緩存的緩沖區(qū)個(gè)數(shù),即25165824/8192=3072個(gè)。

前面已經(jīng)提到,提高數(shù)據(jù)訪問命中率的一個(gè)有效方法是增加數(shù)據(jù)庫(kù)高速緩存的大小。但是由于受到物理內(nèi)存的限制,數(shù)據(jù)庫(kù)高速緩存不可能無限大。如果將數(shù)據(jù)庫(kù)高速緩存設(shè)置得過大,操作系統(tǒng)可以使用的內(nèi)存將減少,這樣就要使用虛擬內(nèi)存,反而會(huì)降低系統(tǒng)性能。所以數(shù)據(jù)訪問的命中率不可能達(dá)到100%。如果用戶訪問的數(shù)據(jù)不在數(shù)據(jù)庫(kù)高速緩存中,就需要把數(shù)據(jù)讀到某個(gè)緩沖區(qū)中。一個(gè)數(shù)據(jù)塊的內(nèi)容到底放在哪個(gè)緩沖區(qū)中,如果沒有足夠的空閑緩沖區(qū)該怎么辦呢?有必要分析一下緩沖區(qū)的使用情況。

根據(jù)緩沖區(qū)的使用情況,可以把緩沖區(qū)分為空閑緩沖區(qū)、臟緩沖區(qū)和忙緩沖區(qū)3種類型。如果一個(gè)緩沖區(qū)中存放的是由SELECT命令檢索的數(shù)據(jù),而且這樣的數(shù)據(jù)沒有被修改過,這樣的緩沖區(qū)就是空閑緩沖區(qū)。如果緩沖區(qū)中存放的是由DML命令處理過的數(shù)據(jù),而且這樣的數(shù)據(jù)已經(jīng)被寫入數(shù)據(jù)塊中,這樣的緩沖區(qū)也是空閑緩沖區(qū)。空閑緩沖區(qū)的內(nèi)容與對(duì)應(yīng)數(shù)據(jù)塊中的內(nèi)容完全一致,這樣的緩沖區(qū)可用來存放用戶即將訪問的數(shù)據(jù)。如果用戶執(zhí)行了INSERT、UPDATE或者DELETE命令,相應(yīng)的訪問將在緩沖區(qū)中進(jìn)行。如果數(shù)據(jù)被修改后還沒有寫入數(shù)據(jù)塊,這時(shí)緩沖區(qū)中的內(nèi)容與數(shù)據(jù)塊不一致,這樣的緩沖區(qū)就是臟緩沖區(qū)。臟緩沖區(qū)中的數(shù)據(jù)必須寫入數(shù)據(jù)文件的數(shù)據(jù)塊中,這個(gè)任務(wù)由后臺(tái)進(jìn)程DBWR(數(shù)據(jù)庫(kù)寫進(jìn)程)完成。臟緩沖區(qū)中的數(shù)據(jù)被寫入數(shù)據(jù)塊后,臟緩沖區(qū)又成為空閑緩沖區(qū)。

忙緩沖區(qū)是指正在被訪問的緩沖區(qū),兩個(gè)用戶進(jìn)程不能同時(shí)訪問同一個(gè)忙緩沖區(qū)。如果用戶進(jìn)程要訪問的數(shù)據(jù)不在緩沖區(qū)中,服務(wù)器進(jìn)程將把對(duì)應(yīng)數(shù)據(jù)塊中的數(shù)據(jù)讀入數(shù)據(jù)庫(kù)高速緩存的空閑緩沖區(qū)中,這個(gè)緩沖區(qū)中以前的數(shù)據(jù)將被覆蓋。現(xiàn)在考慮一種情況:假設(shè)一個(gè)緩沖區(qū)中的內(nèi)容被覆蓋,恰在這時(shí),另一個(gè)用戶進(jìn)程要再一次訪問這個(gè)緩沖區(qū)中以前的數(shù)據(jù),服務(wù)器進(jìn)程將不得不把數(shù)據(jù)所在的數(shù)據(jù)塊重新從數(shù)據(jù)文件讀到另一個(gè)緩沖區(qū)中,這種情況顯然會(huì)降低數(shù)據(jù)庫(kù)的性能。為了確保數(shù)據(jù)訪問的命中率,Oracle采用LRU(Least Recently Used,最近最少使用)算法,確定每次使用的空閑緩沖區(qū)。LRU算法的思想是基于這樣一個(gè)假設(shè):在最近一段時(shí)間內(nèi)使用最少的緩沖區(qū),在以后的一段時(shí)間內(nèi)也將使用最少,而最近一段時(shí)間被頻繁訪問的緩沖區(qū),在以后的一段時(shí)間也將被頻繁訪問,這個(gè)緩沖區(qū)中的數(shù)據(jù)就不應(yīng)該被覆蓋。基于這個(gè)思想,每次將數(shù)據(jù)讀到緩沖區(qū)中時(shí),服務(wù)器進(jìn)程總是選擇那些最近訪問次數(shù)最少的空閑緩沖區(qū)。這種方法雖然不能完全杜絕,但是可以盡量減少上述情況的發(fā)生。

在實(shí)例中維護(hù)了一個(gè)LRU隊(duì)列,在這個(gè)隊(duì)列中記錄了各個(gè)緩沖區(qū)的使用情況。隊(duì)列的操作遵循“先進(jìn)先出”的原則,那些最近訪問最頻繁的緩沖區(qū)位于隊(duì)列尾部,而那些最近最少被訪問的緩沖區(qū)則位于隊(duì)列頭部。

如果用戶訪問的數(shù)據(jù)恰好在緩沖區(qū)中,則該緩沖區(qū)被標(biāo)志為“最近訪問”,并被移動(dòng)到隊(duì)列尾部。如果用戶訪問的數(shù)據(jù)不在緩沖區(qū)中,服務(wù)器進(jìn)程將在隊(duì)列頭部尋找合適數(shù)量的空閑緩沖區(qū),將數(shù)據(jù)讀到這些緩沖區(qū)中,并將它們標(biāo)志為“最近訪問”,然后將它們移動(dòng)到隊(duì)列尾部。

如果在搜索LRU隊(duì)列的過程中遇到一個(gè)忙緩沖區(qū),服務(wù)器進(jìn)程將忽略它。如果找到一個(gè)臟緩沖區(qū),服務(wù)器進(jìn)程將這個(gè)臟緩沖區(qū)寫入另外一個(gè)“臟隊(duì)列”中,然后繼續(xù)查找LRU隊(duì)列,直到找到足夠數(shù)量的空閑緩沖區(qū)。在臟隊(duì)列中記錄了數(shù)據(jù)庫(kù)高速緩存中的臟緩沖區(qū),實(shí)例中的DBWR(數(shù)據(jù)庫(kù)寫進(jìn)程)后臺(tái)進(jìn)程在一定的時(shí)機(jī)下將這個(gè)隊(duì)列中的緩沖區(qū)寫入數(shù)據(jù)文件中。

上面考慮了緩沖區(qū)的一種使用情況,即在數(shù)據(jù)庫(kù)高速緩存總有足夠數(shù)量的空閑緩沖區(qū)。一種經(jīng)常發(fā)生的情況是,在搜索LRU隊(duì)列時(shí)沒有找到足夠數(shù)量的空閑緩沖區(qū),這時(shí)服務(wù)器進(jìn)程將激活實(shí)例中的DBWR(數(shù)據(jù)庫(kù)寫進(jìn)程)后臺(tái)進(jìn)程,將臟隊(duì)列中的臟緩沖區(qū)內(nèi)容寫入數(shù)據(jù)文件中,這些臟緩沖區(qū)重新成為空閑緩沖區(qū),它們將被從臟隊(duì)列中清除,而重新被寫入LRU隊(duì)列,服務(wù)器進(jìn)程將繼續(xù)在LRU隊(duì)列中搜索。

當(dāng)用戶進(jìn)程執(zhí)行事務(wù)時(shí),將在數(shù)據(jù)庫(kù)高速緩存中產(chǎn)生臟緩沖區(qū),這些臟緩沖區(qū)并不是立刻被寫入數(shù)據(jù)文件,而是在一定的時(shí)機(jī)下,由DBWR(數(shù)據(jù)庫(kù)寫進(jìn)程)進(jìn)程一起寫入,這樣做的好處是減少了磁盤I/O,從而提高了數(shù)據(jù)庫(kù)的性能。

前面說過,數(shù)據(jù)塊的大小由初始化參數(shù)DB_BLOCK_SIZE指定,而且不能改變。設(shè)置數(shù)據(jù)塊大小的一個(gè)基本原則是:如果在數(shù)據(jù)庫(kù)中主要執(zhí)行SELECT語(yǔ)句,如在數(shù)據(jù)倉(cāng)庫(kù)中,這個(gè)參數(shù)可以設(shè)置得大一些;如果主要執(zhí)行DML(insert、update、delete)語(yǔ)句,這個(gè)參數(shù)可以設(shè)置得小一些。但是在一個(gè)數(shù)據(jù)庫(kù)中,可能會(huì)對(duì)一部分?jǐn)?shù)據(jù)主要執(zhí)行SELECT語(yǔ)句,對(duì)另一部分?jǐn)?shù)據(jù)主要執(zhí)行DML(insert、update、delete)語(yǔ)句。在這種情況下,可以在數(shù)據(jù)庫(kù)中定義不同的數(shù)據(jù)塊大小,根據(jù)數(shù)據(jù)的不同訪問要求,把它們放在不同的數(shù)據(jù)塊中,從而在整體上提高數(shù)據(jù)庫(kù)的性能。

由初始化參數(shù)DB_BLOCK_SIZE指定的數(shù)據(jù)塊稱為標(biāo)準(zhǔn)塊,在數(shù)據(jù)庫(kù)中還可以定義其他大小的非標(biāo)準(zhǔn)數(shù)據(jù)塊,非標(biāo)準(zhǔn)數(shù)據(jù)塊的大小可以是2KB、4KB、8KB、16KB、32KB等。為了訪問非標(biāo)準(zhǔn)塊中的數(shù)據(jù),在SGA中也需要為它們定義相應(yīng)的數(shù)據(jù)庫(kù)高速緩存,而緩存中緩沖區(qū)大小與非標(biāo)準(zhǔn)塊的大小也是一致的。Oracle提供了一套新的初始化參數(shù)DB_nK_CACHE_SIZE,用于定義與nKB的非標(biāo)準(zhǔn)數(shù)據(jù)塊對(duì)應(yīng)的數(shù)據(jù)庫(kù)高速緩存大小,例如:

●DB_2K_CACHE_SIZE為2KB的數(shù)據(jù)塊定義緩存大小,緩存由2KB的緩沖區(qū)組成;

●DB_4K_CACHE_SIZE為4KB的數(shù)據(jù)塊定義緩存大小,緩存由4KB的緩沖區(qū)組成;

●DB_8K_CACHE_SIZE為8KB的數(shù)據(jù)塊定義緩存大小,緩存由8KB的緩沖區(qū)組成;

……

例如,假設(shè)在參數(shù)文件中有以下初始化參數(shù)。

●DB_BLOCK_SIZ=8192

●DB_CACHE_SIZE=25165824

●DB_2K_CACHE_SIZE=48M

●DB_16K_CACHE_SIZE=56M

這說明標(biāo)準(zhǔn)數(shù)據(jù)塊的大小為8KB,由8KB的緩沖區(qū)組成的數(shù)據(jù)庫(kù)高速緩存為24MB,同時(shí)定義了兩種大小的非標(biāo)準(zhǔn)塊和對(duì)應(yīng)的緩存,由2KB的緩沖區(qū)組成的數(shù)據(jù)庫(kù)高速緩存大小為48MB,由16KB的緩沖區(qū)組成的數(shù)據(jù)庫(kù)高速緩存大小為56MB,總的數(shù)據(jù)庫(kù)高速緩存大小為三者之和。

注意:在上面這種情況下使用初始化參數(shù)DB_8K_CACHE_SIZE是非法的,因?yàn)闃?biāo)準(zhǔn)塊的大小為8KB。

為了使用非標(biāo)準(zhǔn)數(shù)據(jù)塊,首先需要定義對(duì)應(yīng)的數(shù)據(jù)庫(kù)高速緩存,然后在創(chuàng)建表空間時(shí)為數(shù)據(jù)文件指定數(shù)據(jù)塊大小。當(dāng)用戶訪問標(biāo)準(zhǔn)數(shù)據(jù)塊中的數(shù)據(jù)時(shí),數(shù)據(jù)將被讀入與標(biāo)準(zhǔn)塊大小一致的緩沖區(qū)中。同樣,非標(biāo)準(zhǔn)數(shù)據(jù)塊中的數(shù)據(jù)將被讀入與非標(biāo)準(zhǔn)塊大小一致的緩沖區(qū)中。

在SQL*Plus中可以通過SHOW命令查看數(shù)據(jù)塊的大小和每種緩沖區(qū)的大小,默認(rèn)緩沖區(qū)的大小與標(biāo)準(zhǔn)數(shù)據(jù)塊的大小一致。例如,下面的命令將顯示標(biāo)準(zhǔn)數(shù)據(jù)塊的大小。

SQL>SHOW PARAMETER DB_BLOCK_SIZE NAME TYPE VALUE  [代碼編號(hào)0001]

運(yùn)行結(jié)果如圖1-4所示。

圖1-4

下面的命令將顯示16KB緩沖區(qū)的大小:

SQL>SHOW PARAMETER DB 16K CACHE SIZE NAME TYPE VALUE  [0002]

1.2.2 重做日志緩沖區(qū)

重做日志是對(duì)用戶事務(wù)所產(chǎn)生的記錄,通過重做日志能夠重新產(chǎn)生數(shù)據(jù),它是確保數(shù)據(jù)安全的一種重要方法。當(dāng)用戶執(zhí)行DML(Data Manipulation Language,數(shù)據(jù)操縱語(yǔ)言,主要包括INSERT、UPDATE和DELETE),或者DDL(Data Defination Language;數(shù)據(jù)定義語(yǔ)言,主要包括CREATE、DROP、ALTER等)操作時(shí),服務(wù)器進(jìn)程首先將這些操作記錄在重做日志緩沖區(qū)中,然后才去修改相應(yīng)的數(shù)據(jù)。重做日志緩沖區(qū)中的內(nèi)容在一定的時(shí)機(jī)下,被LGWR(日志寫進(jìn)程)后臺(tái)進(jìn)程寫入重做日志文件。如果數(shù)據(jù)庫(kù)系統(tǒng)出現(xiàn)故障,可以根據(jù)重做日志文件中的重做日志對(duì)數(shù)據(jù)庫(kù)進(jìn)行恢復(fù)。

引入重做日志緩沖區(qū)的好處是顯而易見的:將日志記錄在重做日志緩沖區(qū)中,比直接寫入重做日志文件要快得多。另外,LGWR(日志寫進(jìn)程)并不是在每次用戶訪問數(shù)據(jù)之后,都要將重做日志緩沖區(qū)中的日志寫入重做日志文件,而是將最近一段時(shí)間產(chǎn)生的重做日志一起寫入,這樣可以減少訪問磁盤的次數(shù),從而提高系統(tǒng)的性能。

重做日志緩沖區(qū)的大小由初始化參數(shù)LOG_BUFFER指定。在一定的時(shí)機(jī)下,LGWR(日志寫進(jìn)程)后臺(tái)進(jìn)程會(huì)將重做日志緩沖區(qū)中的內(nèi)容寫入重做日志文件。例如,在重做日志緩沖區(qū)被消耗了三分之一時(shí)。由此可見,重做日志緩沖區(qū)越大,就可以記錄越多的用戶操作,寫重做日志文件的次數(shù)也就越少,這樣也可以提高數(shù)據(jù)庫(kù)的性能。當(dāng)然,重做日志緩沖區(qū)的大小是受物理內(nèi)存大小的限制的。

1.2.3 共享池

數(shù)據(jù)庫(kù)中的數(shù)據(jù)是以表的形式組織在一起的。當(dāng)用戶訪問數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)服務(wù)器首先檢查對(duì)應(yīng)的表是否存在,然后檢查指定的列是否存在,還要檢查權(quán)限和加鎖等信息。當(dāng)這些檢查都通過時(shí),數(shù)據(jù)庫(kù)服務(wù)器將對(duì)用戶的命令進(jìn)行分析,產(chǎn)生分析代碼和執(zhí)行計(jì)劃,然后按照這樣的執(zhí)行計(jì)劃訪問數(shù)據(jù),并將執(zhí)行結(jié)果返回給用戶。

為了提高數(shù)據(jù)庫(kù)的性能,Oracle在SGA中開辟了一個(gè)共享池,用于存放與SQL語(yǔ)句的執(zhí)行有關(guān)的信息。共享池主要由3部分組成,即數(shù)據(jù)字典高速緩存、庫(kù)高速緩存和服務(wù)器結(jié)果緩存。共享池的大小由初始化參數(shù)SHARED_POOL_SIZE指定。總的來說,共享池幾乎和數(shù)據(jù)庫(kù)中的所有操作都有關(guān)。

當(dāng)用戶訪問數(shù)據(jù)庫(kù)中的數(shù)據(jù)時(shí),數(shù)據(jù)庫(kù)服務(wù)器首先要查詢相關(guān)的數(shù)據(jù)字典,確定要訪問的對(duì)象是否存在,如表、視圖等,以及表和視圖上的列等。然后檢查權(quán)限等信息,最后才執(zhí)行這樣的命令。數(shù)據(jù)字典信息存儲(chǔ)在SYSTEM表空間中,也就是說,存儲(chǔ)在磁盤上的數(shù)據(jù)文件中。如果數(shù)據(jù)庫(kù)服務(wù)器進(jìn)程每次都要從磁盤上讀數(shù)據(jù)字典信息,那么SQL語(yǔ)句的執(zhí)行效率很低。

為了加快這個(gè)SQL語(yǔ)句的執(zhí)行速度,Oracle在共享池中開辟了數(shù)據(jù)字典緩存,用來存放最近訪問的數(shù)據(jù)字典的信息。這樣,在查詢相關(guān)的數(shù)據(jù)字典時(shí),可以直接在數(shù)據(jù)字典緩存中進(jìn)行。

庫(kù)高速緩存用于存放最近執(zhí)行的SQL命令的相關(guān)信息。數(shù)據(jù)庫(kù)服務(wù)器在執(zhí)行SQL命令時(shí),首先要對(duì)SQL命令進(jìn)行解析,產(chǎn)生分析代碼,并生成執(zhí)行計(jì)劃,然后才按照?qǐng)?zhí)行計(jì)劃執(zhí)行SQL命令,最后把命令的執(zhí)行結(jié)果返回給用戶。在整個(gè)執(zhí)行過程中,分析階段所用的時(shí)間最長(zhǎng)。如果能減少分析所用的時(shí)間,那么整個(gè)SQL命令的執(zhí)行效率將大大提高。Oracle的做法是:在執(zhí)行一條SQL命令時(shí),服務(wù)器進(jìn)程對(duì)它進(jìn)行分析,然后把SQL命令文本、解析結(jié)果和執(zhí)行計(jì)劃存儲(chǔ)在庫(kù)高速緩存中。

服務(wù)器進(jìn)程在執(zhí)行一條SQL命令時(shí),首先要到庫(kù)高速緩存中查看是否存在這條SQL命令的信息,如果發(fā)現(xiàn)SQL語(yǔ)句相關(guān)信息已經(jīng)存儲(chǔ)在庫(kù)高速緩存中,就直接取出執(zhí)行計(jì)劃并執(zhí)行它,這樣就省去了分析所用的時(shí)間,可以大大加快SQL命令的執(zhí)行速度。否則,服務(wù)器進(jìn)程需要按部就班地對(duì)SQL命令進(jìn)行解析,然后生成執(zhí)行計(jì)劃,并將這些信息存儲(chǔ)在庫(kù)高速緩存中。

當(dāng)兩條SQL命令的文本完全相同時(shí),認(rèn)為它們是同一條命令,這時(shí)它們可以共享庫(kù)高速緩存中的信息。如果命令文本中的大小寫、空格個(gè)數(shù)或參數(shù)的數(shù)值不同,就認(rèn)為是兩條不同的命令,它們?cè)趫?zhí)行時(shí)需要單獨(dú)進(jìn)行分析,最終將生成不同的分析代碼和執(zhí)行計(jì)劃。例如,考慮以下兩條命令:

SELECT ename,sal FROM emp WHERE eno=7902

SELECT ENAME,SAL FROM EMP WHERE EN0=7902  [0003]

這兩條命令看似相同,實(shí)際上是有差別的。首先,命令中的大小寫不同。其次,兩個(gè)列之間的空格個(gè)數(shù)不同,所以它們將生成不同的分析代碼和執(zhí)行計(jì)劃。由此可見,命令的書寫風(fēng)格對(duì)命令的執(zhí)行結(jié)果沒有什么影響,但對(duì)命令的執(zhí)行效率卻大有影響。

在這里,給程序員一個(gè)建議:開發(fā)程序時(shí)要考慮編程的風(fēng)格和程序的執(zhí)行效率。雖然每個(gè)程序員都會(huì)編程,但是不同的程序員編寫的程序的執(zhí)行效率是大不一樣的。實(shí)踐證明,在很多生產(chǎn)系統(tǒng)中,程序員編寫的程序就是整個(gè)系統(tǒng)性能的瓶頸,這樣的系統(tǒng)在提交用戶后,管理員對(duì)此是無能為力的。

1.2.4 Java池

Java池是SGA中兩段可選的存儲(chǔ)區(qū)域。如果要在數(shù)據(jù)庫(kù)中運(yùn)行Java應(yīng)用程序,那么對(duì)用戶的每個(gè)會(huì)話來說,都需要一個(gè)單獨(dú)的Java虛擬機(jī)。實(shí)際情況是,每個(gè)Java虛擬機(jī)僅僅需要很小的一段內(nèi)存空間,大約35KB。Java虛擬機(jī)為什么能在這么小的內(nèi)存空間中運(yùn)行呢?

在實(shí)例啟動(dòng)時(shí),可以在SGA中分配一個(gè)Java池,用來存放運(yùn)行Java所必需的共享代碼和共享數(shù)據(jù)。多個(gè)Java應(yīng)用程序可以共享Java池中的代碼和數(shù)據(jù)。在有些情況下,每個(gè)用戶的Java會(huì)話信息也存儲(chǔ)在Java池中。

Java池的大小由初始化參數(shù)JAVA_POOL_SIZE指定,默認(rèn)大小為20MB,在運(yùn)行Java應(yīng)用程序時(shí),每個(gè)類需要4~8KB的Java池空間,這樣可以根據(jù)Java應(yīng)用程序中類的個(gè)數(shù)來估計(jì)一下所需的Java池空間。

另外,還可以通過查詢動(dòng)態(tài)性能視圖v$sgastat來了解Java池的使用情況。例如:

SQL>SELECT * FROM v$sgastat WHERE pool=' java pool' ;  [0004]

運(yùn)行結(jié)果如圖1-5所示。

圖1-5

1.2.5 PGA(程序全局區(qū))

PGA(Program Global Area,程序全局區(qū))是內(nèi)存中一段特殊的區(qū)域,它包含了服務(wù)器進(jìn)程的數(shù)據(jù)和控制信息,它是一段非共享的內(nèi)存區(qū)域。當(dāng)服務(wù)器進(jìn)程啟動(dòng)時(shí),數(shù)據(jù)庫(kù)服務(wù)器為它分配一段PGA,這個(gè)PGA只能由當(dāng)前服務(wù)器進(jìn)程訪問。實(shí)際上,PGA并不屬于實(shí)例,而是屬于服務(wù)器進(jìn)程私有的。

PGA包括兩個(gè)部分:私有SQL區(qū)和會(huì)話內(nèi)存區(qū)。

(1)私有SQL區(qū)

在私有SQL區(qū)中保存了SQL語(yǔ)句的綁定信息和運(yùn)行時(shí)的內(nèi)存結(jié)構(gòu)。當(dāng)用戶執(zhí)行一條SQL語(yǔ)句時(shí),服務(wù)器進(jìn)程即為這條語(yǔ)句分配一段私有SQL區(qū)。如果兩個(gè)用戶執(zhí)行了相同的SQL語(yǔ)句,那么這兩段私有SQL區(qū)就被映射為一個(gè)共享的SQL區(qū)。

當(dāng)用戶執(zhí)行SQL語(yǔ)句時(shí),將顯式或隱式地使用游標(biāo),每個(gè)游標(biāo)都有一段私有SQL區(qū)。私有SQL區(qū)由持久區(qū)和運(yùn)行時(shí)區(qū)組成,其中持久區(qū)保存SQL語(yǔ)句的綁定信息,僅當(dāng)游標(biāo)關(guān)閉時(shí)它才被釋放。運(yùn)行時(shí)區(qū)是在服務(wù)器進(jìn)程接收到SQL語(yǔ)句的執(zhí)行請(qǐng)求時(shí)才產(chǎn)生的,在語(yǔ)句執(zhí)行結(jié)束時(shí)被釋放。

私有SQL區(qū)的位置與會(huì)話的連接方式有關(guān)。如果會(huì)話以專用方式與數(shù)據(jù)庫(kù)服務(wù)器連接,那么它位于服務(wù)器進(jìn)程的PGA中。如果會(huì)話以共享方式連接數(shù)據(jù)庫(kù)服務(wù)器,那么它將位于SGA中。

(2)會(huì)話內(nèi)存區(qū)

會(huì)話內(nèi)存區(qū)保存會(huì)話變量和其他會(huì)話信息。對(duì)于共享服務(wù)器,這部分內(nèi)存區(qū)是共享的,而不是私有的,這些信息被所有的共享服務(wù)器進(jìn)程所共享。

對(duì)于復(fù)雜的查詢操作,私有SQL區(qū)中的運(yùn)行時(shí)區(qū)大部分被用作排序、位圖的創(chuàng)建、位圖的合并等特殊操作,這部分特殊區(qū)域叫作“SQL工作區(qū)”。例如,用戶執(zhí)行排序操作時(shí),要用到排序區(qū),排序區(qū)就位于SQL工作區(qū)中。

SQL工作區(qū)的大小是可以控制的。這部分內(nèi)存區(qū)域越大,數(shù)據(jù)庫(kù)的性能就越高。如果這部分內(nèi)存區(qū)域的大小不足以執(zhí)行排序等操作,那么將使用臨時(shí)表空間中的臨時(shí)段。

在以前的Oracle版本中,用于排序、位圖索引的創(chuàng)建等操作的內(nèi)存區(qū)域分別由初始化參數(shù)SORT_AREA_SIZE、CREATE_BITMAP_AREA_SIZE、BITMAP_MERGE_AREA_SIZE等指定。在Oracle 11g中,可以對(duì)這部分內(nèi)存區(qū)域進(jìn)行自動(dòng)管理。首先通過設(shè)置初始化參數(shù)WORKAREA_SIZE_POLICY,將SQL工作區(qū)的管理方式設(shè)置為自動(dòng)方式,然后設(shè)置初始化參數(shù)PGA_AGGREGATE_TARGET,指定SQL工作區(qū)的大小。用戶在進(jìn)行排序等操作時(shí),使用的內(nèi)存區(qū)域的總和不能超過SQL工作區(qū)的大小,服務(wù)器進(jìn)程將根據(jù)用戶操作的需求,自動(dòng)分配所需的內(nèi)存區(qū)域。

初始化參數(shù)WORKAREA_SIZE_POLICY的值有兩個(gè):AUTO和MANUAL。如果設(shè)置為AUTO,則SQL工作區(qū)的管理自動(dòng)進(jìn)行,這時(shí)就不需要通過SORT_AREA_SIZE等初始化參數(shù)為不同的操作分別指定內(nèi)存區(qū)域,只要通過初始化參數(shù)PGA_AGGREGATE_TARGET指定PGA的大小即可。如果設(shè)置為MANUAL,那么需要分別為用戶的各種操作指定所需內(nèi)存區(qū)域的大小。

主站蜘蛛池模板: 鄱阳县| 施秉县| 铁岭市| 保靖县| 文水县| 碌曲县| 湾仔区| 徐州市| 普陀区| 玉屏| 临城县| 阳城县| 成安县| 大城县| 乌苏市| 凤翔县| 息烽县| 大悟县| 丹江口市| 灵宝市| 金寨县| 陈巴尔虎旗| 太和县| 乌鲁木齐县| 始兴县| 肇州县| 庆阳市| 宝应县| 通海县| 军事| 水城县| 景东| 宾川县| 镇宁| 昌图县| 弋阳县| 衡阳县| 简阳市| 高邑县| 杂多县| 芜湖县|