Oracle數(shù)據(jù)庫由 `實例` 和 `數(shù)據(jù)庫` 兩部分構(gòu)成。Oracle數(shù)據(jù)庫啟動后,會在操作系統(tǒng)內(nèi)存中劃分出來一塊獨立的區(qū)域,并且在后臺啟動一些進程,而劃分出來的內(nèi)存和后臺進程統(tǒng)稱為 `實例`。
`實例` 為訪問數(shù)據(jù)庫提供了入口,通常來說,一個數(shù)據(jù)庫對應(yīng)一個數(shù)據(jù)庫的實例。而在某些特殊的結(jié)構(gòu)中,一個數(shù)據(jù)庫會對應(yīng)多個數(shù)據(jù)庫實例。例如,一個 `RAC` 數(shù)據(jù)庫會對應(yīng)至少兩個數(shù)據(jù)庫的實例。
而數(shù)據(jù)庫在啟動過程中向操作系統(tǒng)內(nèi)存申請的內(nèi)存則稱為 `SGA(System Global Area,系統(tǒng)全局區(qū))`。`系統(tǒng)全局區(qū)SGA` 是一組共享內(nèi)存結(jié)構(gòu),其中包含Oracle數(shù)據(jù)庫的數(shù)據(jù)文件信息和控制文件信息。SGA提供給所有Oracle數(shù)據(jù)庫的實例和后臺進程共享,因此,系統(tǒng)全局區(qū)也被稱為 `共享全局區(qū)(Shared Gloabl Area)`。
在數(shù)據(jù)庫啟動后,內(nèi)存中的一塊獨立區(qū)域(可能是提前劃分好的)被用來存放Oracle數(shù)據(jù)庫的一些基本信息,而這塊劃分出來的區(qū)域 `SGA` 通常包含以下6個部分,`Shared Pool(共享池)`、`Stream Pool(流池)`、`Large Pool(大型池)`、`Java Pool(java池)`、`Database Buffer Cache(數(shù)據(jù)庫緩沖區(qū)高速緩存)` 和 `Redo Log Buffer(重做日志緩沖區(qū))`。
如下圖,為Oracle SGA內(nèi)存結(jié)構(gòu)圖

-
Database Buffer Cache: Oracle實例SGA內(nèi)存區(qū)域至關(guān)重要的一塊內(nèi)存區(qū)域。主要用于提升數(shù)據(jù)庫的訪問性能。通常,當(dāng)用戶進程連接到數(shù)據(jù)庫實例時,在數(shù)據(jù)庫中會產(chǎn)生大量的I/O請求,而當(dāng)用戶進程需要查詢或修改的數(shù)據(jù)庫不在內(nèi)存(`Database Buffer Cache`)高速緩沖區(qū)中時,不可避免需要將數(shù)據(jù)庫存儲在硬盤上的數(shù)據(jù)加載到高速緩存區(qū)中,而每當(dāng)數(shù)據(jù)庫需要從硬盤中提取數(shù)據(jù)到緩沖區(qū)時,則需要進行操作系統(tǒng)層面的I/O操作。 而倘若用戶進程連接到數(shù)據(jù)庫中的查詢請求的數(shù)據(jù)已經(jīng)存在在 `Database Buffer Cache` 中時,數(shù)據(jù)庫會直接從緩沖區(qū)中讀入數(shù)據(jù)并將數(shù)據(jù)返回給用戶請求。當(dāng)請求數(shù)據(jù)被從數(shù)據(jù)庫緩沖區(qū)中返回時,則稱為一次緩存命中(hit)。顯然,數(shù)據(jù)庫中緩存命中可以極大提升數(shù)據(jù)庫的訪問性能。 也因此,數(shù)據(jù)庫的 `Database Buffer Cache` 內(nèi)存區(qū)域的空間應(yīng)該盡可能大一些,從而減少數(shù)據(jù)庫進入硬盤讀取數(shù)據(jù)而產(chǎn)生的I/O事件。 但受限于操作系統(tǒng)內(nèi)存的容量限制,`SGA` 不可能無限制的大。因此,`SGA` 內(nèi)存結(jié)構(gòu)中的各個結(jié)構(gòu)區(qū)域也有各自的大小。而當(dāng) `Database Buffer Cache` 高速緩存區(qū)被塞滿時,則需要清除掉部分不經(jīng)常被訪問的數(shù)據(jù),以便將緩存中經(jīng)常需要訪問的數(shù)據(jù)保留下來實現(xiàn)更高的緩存命中率,提升數(shù)據(jù)庫的訪問性能。 當(dāng)下一次用戶進程請求 `Database Buffer Cache` 中并不存在的數(shù)據(jù)時,數(shù)據(jù)庫則會重新進入硬盤中找到并提取數(shù)據(jù)到高速緩沖區(qū)中。數(shù)據(jù)庫高速緩沖區(qū)中主要包含三種類型的數(shù)據(jù)塊,根據(jù)數(shù)據(jù)塊的類型分為 `臟數(shù)據(jù)區(qū)(Dirty Buffers)`、`自由區(qū)(Free Buffers)`、 `保留區(qū)(Pinned Buffers)`。
臟數(shù)據(jù)區(qū): 指數(shù)據(jù)庫中的數(shù)據(jù)被修改后尚未寫入到硬盤中。在數(shù)據(jù)庫中,僅寫入到磁盤中的數(shù)據(jù)才會被稱為干凈數(shù)據(jù)。因為數(shù)據(jù)庫緩存區(qū)的數(shù)據(jù)極有可能因為各種原因無法寫入到硬盤中,造成數(shù)據(jù)丟失從而導(dǎo)致數(shù)據(jù)庫出現(xiàn)數(shù)據(jù)不一致的問題。
自由區(qū): 指數(shù)據(jù)庫中的干凈區(qū)域,沒有被使用過的區(qū)域。自由區(qū)中,數(shù)據(jù)庫可以隨時向該區(qū)域?qū)懭霐?shù)據(jù),通常從硬盤中讀入的數(shù)據(jù)會放入干凈區(qū)中。
保留區(qū): 涉及到修改或正在操作的區(qū)域,或有其他用途的區(qū)域。
-
Shared Pool: 共享池緩存。主要用來存儲可以被不同用戶共享的重復(fù)SQL語句、數(shù)據(jù)字典中的信息。共享池是SGA中用來緩存程序數(shù)據(jù)的區(qū)域。主要包含 **可重用的SQL語句**、**數(shù)據(jù)字典信息**、**SQL存儲過程**等。共享池主要包含兩個部分,一部分是 `Library Cache`,另一部分是 `Data Dictionary Cache`。
Libray Cache 主要用來緩存用戶執(zhí)行過的SQL語句及PL/SQL的相關(guān)信息,緩存的主要信息包含用戶執(zhí)行過的SQL語句文本、執(zhí)行結(jié)果及執(zhí)行計劃。位于該緩存區(qū)的SQL語句或執(zhí)行計劃同時會共享給其他不同的用戶,當(dāng)其他用戶在數(shù)據(jù)庫中執(zhí)行同樣的SQL語句或執(zhí)行計劃時,位于 Libray Cache 緩存區(qū)的執(zhí)行結(jié)果將返回給其他用戶而無需重新在數(shù)據(jù)庫中執(zhí)行一次相同的SQL語句。
顯然當(dāng)數(shù)據(jù)庫中有大批用戶需要查詢相同的數(shù)據(jù)時,使用系統(tǒng)的sql語句會極大提高數(shù)據(jù)庫的響應(yīng)速度,而這正是因為數(shù)據(jù)庫的相同的SQL語句文本及執(zhí)行結(jié)果、執(zhí)行計劃被緩存到 `Linrary Cache` 中了。
Data Dictionary Cache: 該部分緩存區(qū)主要緩存數(shù)據(jù)字典相關(guān)的一些信息,例如,用戶賬戶數(shù)據(jù)、數(shù)據(jù)表及索引、及權(quán)限等信息。使用數(shù)據(jù)字典緩存,可以縮短數(shù)據(jù)的解析響應(yīng)時間。
-
Redo Log Buffer: 重做日志緩沖區(qū),主要用來記錄數(shù)據(jù)庫發(fā)生的事務(wù)變更。通常用戶進程連接到數(shù)據(jù)庫后,不可避免需要對數(shù)據(jù)中的數(shù)據(jù)進行增刪改善,而涉及到被修改的數(shù)據(jù),Oracle數(shù)據(jù)庫會將被修改的數(shù)據(jù)相關(guān)信息寫入到 `Redo Log Buffer` 中,最后通過 `LGWR` 后臺進程將緩存區(qū)的日志寫入到 Redo Log 日志文件中。 需要注意的是,Oracle數(shù)據(jù)庫對于已修改數(shù)據(jù)并不是數(shù)據(jù)發(fā)生修改后直接寫回到硬盤的,而是將修改數(shù)據(jù)后產(chǎn)生的相關(guān)信息寫入到日志中,而 `Redo Log Buffer` 緩存區(qū)的日志按照一定的規(guī)則將數(shù)據(jù)庫變更的記錄刷新到日志文件中。`Redo Log Buffer` 緩存區(qū)的容量并不會很大,而緩存區(qū)的日志寫入到日志文件中也是按照數(shù)據(jù)發(fā)生修改的時間點按**順序?qū)懭?*,因此寫入日志的性能要高于將數(shù)據(jù)寫回到磁盤中。 Redo Log 所記錄的日志文件對于Oracle數(shù)據(jù)庫的故障恢復(fù)有著非常重大的幫助。通過將修改后的數(shù)據(jù)寫入到redo log日志文件中,即便處于緩存區(qū)的數(shù)據(jù)沒有寫入到硬盤上時數(shù)據(jù)庫發(fā)生了故障,也能在數(shù)據(jù)庫下一次啟動時通過應(yīng)用 redo log 日志中的記錄將數(shù)據(jù)庫再一次恢復(fù)到數(shù)據(jù)庫崩潰前的狀態(tài),保障數(shù)據(jù)的一致性。 -
Large Pool: 大池,主要用于緩存數(shù)據(jù)庫中的大型I/O請求。在一些場景下,數(shù)據(jù)庫會出現(xiàn)大量并行查詢的進程,而并行查詢會產(chǎn)生從屬進程,這些從屬進程需要消耗額外的內(nèi)存空間,而這些空間正式由
Large Pool提供的。另外,在一些共享模式(Shared Server)的場景下,用戶連接所需要的共享內(nèi)存也會由Large Pool分配。在備份恢復(fù)的時候,啟用異步I/O需要設(shè)置Large Pool以支持異步I/O模式。
-
Java Pool: java池,數(shù)據(jù)庫中運行java代碼時需要使用該內(nèi)存區(qū)域。
-
Stream Pool: 流池。數(shù)據(jù)庫中的數(shù)據(jù)可以通過流的方式共享。使用Oracle流,共享信息的每個單元稱為一條消息,可以在流中共享一條條消息。流不僅可以在數(shù)據(jù)庫中共享信息,而且支持在數(shù)據(jù)庫間共享信息,使用流可以將一個數(shù)據(jù)庫的信息傳播到另一個數(shù)據(jù)庫。
參考: SGA、 oracle SGA詳解