SGA系統全域性區記憶體結構瞭解

xiayulai發表於2008-04-11

System global area(SGA) 是一組共享的記憶體結構,它裡面儲存了oracle資料庫例項(instance)的資料和控制檔案資訊。如果有多個使用者同時連線到資料庫,他們會共享這一區域,因此SGA也稱之為shared global area

SGAoracle的程式組成了oracle的例項(instance)。在例項啟動的時候記憶體會自動分配,當例項shutdown的時候作業系統會將記憶體回收的。沒一個例項(instance)擁有自己的SGA

SGA是可以讀寫的,每一個使用者連到資料庫例項時都是可以讀例項的SGA的內容,oracle透過伺服器程式執行一個命令去寫SGA的資料。

SGA包含以下的資料結構:

l Database buffer cache

l Redo log buffer

l Shared pool

l Java pool

l Large pool (optional)

l Data dictionary cache

l Other miscellaneous information

SGA中還包含了後臺程式訪問的一些關於資料庫和例項狀態的資訊,稱之為fixed SGA,使用者的資訊是不會儲存在這塊區域中的。程式之間的一些交流的資訊也會儲存在SGA中。如果使用共享server模式,有些PGA的內容也會儲存在SGA中。

SGA是可以動態調整大小的,也就是說調整其大小是不用shutdown資料庫的。在初始化引數中設定可以設定sga_max_size這個引數,當SGA的各部分的和要大於設定的sga_max_size的引數的時候,設定的sga_max_size將會被忽略掉,而是將各部分的大小相加。當sga_max_size的大小大於各部分的大小相加時,會使用sga_max_size的引數。

對於效能的考慮,SGA區域的記憶體應該是真正的記憶體,如果使用需擬記憶體,會大大降低效能。下面這幾個引數最嚴重的影響到了SGA的大小:

DB_CACHE_SIZE

The size of the cache of standard blocks.

LOG_BUFFER

The number of bytes allocated for the redo log buffer.

SHARED_POOL_SIZE

The size in bytes of the area devoted to shared SQL and PL/SQL statements.

LARGE_POOL_SIZE

The size of the large pool; the default is 0.

SGA分配的最小單元

SGA在分配和回收的時候是採用一個叫做granule的單元進行分配的,granule的大小是由SGA的大小決定的,如果SGA小於128mb,則granule就是4mb,大於128mb,則為8mb或者16mb,當分配記憶體的時候,將會以granule的整數倍去分配,比如設定DB_CACHE_SIZE=131mbgrance4mb時,系統會將DB_CACHE_SIZE=132mb所有關於granule的資訊都會儲存在granule entry,在granule entry中管理每個granule的狀態等資訊。

Database buffer cache

Database buffer cache SGA中的一部分,它儲存的是從資料檔案中讀取的資料塊的複製,所有的資料庫連線都會共享訪問這個區域。Database buffer cache sql的共享區分在不同的邏輯segment集中(database buffer cache shared pool 是不同的兩個記憶體區域),這樣可以降低他們之間的爭用情況。

Database buffer cache的組織方式

這塊記憶體區域中被組織成兩個連結串列:一個是寫的連結串列,一個是最近最少使用(LRU)的連結串列。寫的連結串列裡面是寫髒資料的,LRU連結串列是控制不包含任何資料的空閒空間(free buffers)、正在使用的空間(pinned buffers)和還沒有寫到寫連結串列的髒資料塊。

當一個程式訪問一個buffer的時候,程式將會將該buffer移到LRU的末尾,稱之為MRU,當越來越多的buffer被移到MRU後,髒資料塊就會接近LRULRU端。

開始的時候,使用者程式需要一些資料,它就會到database buffer cache中去搜尋,如果有(cache hit),該程式就可以直接從記憶體中讀資料;如果沒有找到(cache miss),那麼必須先要從資料檔案將資料拷到database buffer cache,然後再去從記憶體中去訪問。Cache hit 要比cache miss 快很多由此可以看出。

在讀一個資料塊到記憶體中去的時候,程式必須先要找到一個空閒的buffer,這時候程式會從LRU的末尾開始訪問LRU連結串列,直到找到一個空閒的buffer 或者搜尋完可以搜尋的所有buffer

當程式在搜尋LRU的時候找到一個髒資料buffer,它就會將該buffer移到write list,然後繼續查詢,直到找到一個空閒buffer,然後候就從硬碟將資料塊讀到這個buffer並且將這個buffer移到LRU的末尾MRU端。如果這個使用者程式找遍了所有的buffer也沒有找到一個空閒的buffer,這時候就停止查詢LRU,告訴DBW0去寫一些髒資料塊到硬碟。

LRU演算法和全表掃描

當使用者程式執行一個全表掃描的時候,它就會讀表的所有塊到buffer並且將他們放在LRULRU端的連結串列上,因為全表掃描的資料基本上就是比較簡短的使用就不再使用了,所以他應該放在LRULRU端的連結串列上的,用完了就需要趕緊交換出去了。

也可以採用一些方法改變這樣的一個全表掃描的buffer處理行為,cache可以將表等cacheMRU的末尾,這樣可以避免一些io的消耗,當然這樣的表應該是比較小的。

根據上面,我對database buffer cache的理解LRU是一個什麼樣的連結串列:

LRU

----------------------------------------------------

| buffer| buffer| ..... |buffer|buffer|

-MRU端-----------------------------------LRU端------

因為SGA中只有兩個連結串列:一個是WRITE連結串列,一個是LRU連結串列。所以MRULRU應該是一個LRU連結串列中的,而LRUMRU端是最近最多訪問的,LRULRU端是最近最少訪問的。個人認為write連結串列在一開始沒有髒資料需要寫的時候是一個空連結串列,當有髒資料bufferLRU連結串列移過來時,這個連結串列開始有buffer鏈在上面,其實此時是不會再另外為寫連結串列分配空間的,直接將LRU中的buffer的指標指向寫連結串列就可以了。

Size of the database buffer cache

Oracle允許塊的大小有多種,可以設定db_cache_size的大小。

Redo Log Buffer

buffer是迴圈的一塊空間在SGA中,它儲存了一些關於資料庫的一些改變。這些資訊就儲存在redo entries,包含在執行INSERT, UPDATE, DELETE, CREATE, ALTER, or DROP 操作時的重構或重做的資訊,在恢復的時候,redo entries也許是有必要的。

Redo entries是資料庫伺服器程式從使用者的記憶體空間中複製到redo log bufferredo entries是一個連續的buffer 空間。後臺程式LGWRredo log bufferactive online log file到磁碟上。

Shared pool

這一塊區域裡面三個主要的部分:library cache,dictionary cache,儲存並行執行的資訊的buffer,還有一些控制資訊。

Library cache

這塊區域中有共享的sql區域。私有的sql區域,PL/SQL的程式和包,還有一些鎖和library cache的控制程式碼。

共享的sql區域和私有的sql區域

Oracle會讓每一條sql語句在共享sql區和私有sql區執行,oracle認為,兩個使用者執行相同的sql,此時這些sql應該是可以共享的,然而每一個使用者還會擁有自己的會話環境,這樣就會擁有一個私用的sql區域。

共享sql區域中包含sql的分析樹和執行計劃,oracle會儲存這部分記憶體在共享的sql區中以便使用者可以多次執行這些sql。當一些新的sql執行的時候,oracle會從shared pool中分配一些記憶體給這條sql,記憶體的大小取決於sql的複雜度。如果整個共享區已經被分配完了,oracle會採用LRU策略將一些buffer flush出去直到空閒的buffer可以將新來的sql放得開,被flush出去的sql的一些資訊,下一次再使用的時候需要重新編譯。

私有sql區域包含執行時的一些記憶體結構和一些 bind資訊,每一個會話在執行sql的時候都會有自己的一個sql區域。

遊標的私有sql區域被分為兩種生命週期不相同的區域:

l 持久區域:例如 bind 資訊,這部分空間只有在這個遊標關閉的時候才會被回收。

l 執行時環境:當該sql執行結束的時候這部分環境就會被回收。

Oracle首先會去建立這個執行時環境在執行請求發過來後,對於insert update delete 操作,oracle會在執行完畢後就釋放這部分空間,當執行select 的時候,oracle會到所有行都被fetch或者查詢取消才會釋放這部分空間。

私有sql區域的分配地址是取決於建立連線的session的型別的,如果是從專有伺服器模式下,該私有sql區域會分配在pga中,如果是共享伺服器,該私有sql區域會分配在sga中。

Dictionary cache

資料字典是資料庫的一組表和檢視,它包含資料庫的結構、使用者等的各種資訊。Oracle在解析sql語句的時候會頻繁的去訪問這些表,對於資料庫的這些操作是必不可少的。因為這些資料非常經常的被訪問,所以有兩個地方存放這些資料在記憶體中。一個地方叫 data dictionary cache,也稱之為 row cache,因為在在這塊區域中儲存的是以行的方式做的。另一個地方叫做library cache,所有的使用者都是共享訪問這兩個地方的。

共享記憶體的分配和重用

一般來說,在記憶體中的一些條目一直會保留著的,除非需要按照LRU演算法從記憶體中flush掉,如果有記憶體的需求,有些不用的就會被flush掉。

當一條sql提交到oracle進行執行的時候,oracle一般會執行分配的以下步驟:

1、 到共享池中去檢查要執行的sql是否存在,如果存在就直接使用,如果不存在就需要在共享sql區中分配記憶體,存放新編譯的sql。不論哪一種情況,都有私有sql區都會和使用者的共享區的sql相關聯。

2、 Oracle會分配一個私有的sql區和會話對應,

Oracle在以下情況下會將共享sql區從共享池中flush掉:

l 當使用analyze的時候,所有涉及的物件,都會被flush掉,下一次使用時會重新分配;

l 當一個物件被修改了,其相應的sql也會被flush掉;

l 改變資料庫的全域性名,所有的sql都會被flush掉;

l ALTER SYSTEM FLUSH SHARED_POOL時,所有的sql也會被flush

[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/7312700/viewspace-1002341/,如需轉載,請註明出處,否則將追究法律責任。

相關文章