為什么oracle可以對於大量數據進行訪問時候能彰顯出更加出色表現,就是通過所謂的快速緩存來實現數據的快速運算與操作。在之前的博文中我已經說過sql的運行原理,當我們訪問數據庫的數據時候,首先不是從數據文件里去查詢這個數據,而是從數據快速緩存中去查找,而沒有這個必要再去查詢磁盤中的數據文件了。
僅僅有在數據緩存中沒有這個數據的時候,數據庫才會從數據文件里去查詢(這樣做的目的就是提高讀取的速度,由於讀取內存的速度遠比讀取磁盤的速度快好多倍)。
有了這樣的機制就能提高數據庫的總體效率。
這樣的機制固然提高了數據庫的訪問效率,可是我們不禁會問數據庫是怎樣實現數據文件和快速緩存的一致性的那?在弄清這個問題之前我們先來看一下oracle的體系結構。
在oracle中。oracle的體系結構是有內存結構和進程結構共同組成:
由此可見我們所要研究的數據快速緩存是SGA一部分,那么我們就來說一下SGA的數據結構:
第一部分:數據緩存區
數據緩存區就是我們將數據庫文件的數據存放的緩存。它用來保存從數據文件里讀取近期的數據塊信息。當中的數據被全部用戶享用。數據緩存區有很多大小同樣的緩存塊組成,這些緩存塊大致能夠分為3類:
一、 空暇緩存塊
當我們又一次啟動數據庫后。系統就會為數據庫分配一些空暇的緩存塊。
空暇緩存塊中是沒有不論什么數據的,他們在等待后台進程或server進程向當中寫入數據。當Oracle 數據庫從數據文件里讀取數據后,數據庫就會尋找是否有空暇的緩存塊,以便將數據寫入當中。
一般來說。數據庫在啟動的時候,就會在內存中預先分配這些緩存塊。
所以,Oracle數據庫在啟動的時候,會占用比較多的內存(這個內存空間是能夠設置的)。可是,這能夠免去在實際須要時向內存申請的時間。所以,有時候Oracle數據庫盡管已啟動,內存的占用率就非常高。可是。其興許仍然能夠正常執行的原因。而其它數據庫盡管剛啟動的時候內存占用率不是非常高,可是。但系統內存到達80%以上時,在進行數據處理就會受到明顯的影響。
所以,當我們利用SELECT語句從數據庫文件里讀取文件的時候,數據庫首先會尋找是否有空暇的緩存。
二、命中緩存塊
命中緩存塊保存那些正在使用的數據。
當select語句先從數據庫文件里讀取數據后,會把取得的數據放入到這個命中緩存塊中。
直到快速緩存消耗完成等原因,這個空間才會被釋放。如此下次假設再次訪問同樣的數據的時候就能夠從這里進行查找,節省時間(由於僅僅是被select。因此這里的數據是不會換出內存)。
三、臟緩存塊
臟緩存塊保存已經被改動可是還沒有被寫入數據庫文件的數據。當訪問完數據之后。由空暇緩存塊標志轉化為命中緩存塊標志。當我們運行update這類帶侵略性的操作的時候,我們要先去命中緩存區去尋找數據,假設存在就行直接操作。而且此時命中緩存區標志被轉為臟緩存塊標志。這樣就行實現數據的一致性。當滿足一定的條件時。這些臟緩存塊中的數據內容會被寫入到數據庫文件里去,以便永久性的保留數據庫改動記錄。
當寫入數據庫之后臟緩存塊標志就會轉化為空暇緩存塊。
那Oracle數據庫關於實現三大緩存塊標志轉化的原理:
實現以上機制主要靠兩個列表:1.近期最少使用列表(LRU列表); 2.寫入列表(DIRTY表).當中LRU列表保存着所有空暇緩存塊、命中緩存塊和所有還沒有被移入到DIRTY列表中的臟緩存塊。
當Oracle數據庫用戶在查詢數據的時候。可能會遇到例如以下情況:
1、查詢數據時。數據庫首先在LRU列表中查詢是否有空暇緩存塊。其查詢的數據是從尾部開始查找。當查找有空暇的緩存塊時,數據庫就會把查到的數據寫入到這個空暇緩存中。
2、若數據庫在查詢的時候。首先查到的是臟緩存的話,則會把這個臟緩存移動到DIRTY列表中。然后再繼續查詢。直到查詢到合適的空暇緩存塊為止(查詢的時候數據發生變動)。
3、若數據庫在LRU列表中,從尾到頭查了一遍(忽略oracle的查找算法)。沒有找到空暇緩存塊,或者盡管有空暇緩存塊,可是其容量不符合要求時,數據庫就會臨時結束這一次查找。然后,系統就會觸發數據庫寫進程,把DIRTY列表中的臟緩存塊寫入到數據庫中去。已經被寫入到數據庫文件里去的臟緩存塊將又被數據庫標記為空暇緩存塊。並插入到LRU列表中。當數據庫運行完成這個動作之后。數據庫又會對LRU列表進行搜索,找到合適的數據快速空暇緩存之后,就會把讀取的數據寫入到這個空暇緩存中。
第二部分:重做日志快速緩存
用於記錄數據庫發生改變的信息。這些變化可能是DML或者DDL。關於DML和DDL我已經描寫敘述過。
第三部分:共享池
主要包含庫緩存、數據字典緩存以及用於存儲並行操作信息和控制結構的緩存
庫緩存:解析用戶進程提交的SQL語句或者pl/sql程序和保存近期解析過的程序;
數據字典緩沖區:保存數據庫對象的信息,包含用戶賬號信息、數據文件名稱、段名、表說明、權限等。
第四部分:JAVA池
主要為JAVA命令提供語法解析(用不到JAVA命令無需配置)。
第五部分:大池
數據庫管理員配置的可選內存區域。用於分配大量的內存,處理比共享池更大的內存。須要處理的操作有:數據庫備份與恢復;運行並行化的數據庫操作;具有大量排序的sql等。