讀與寫是每個數(shù)據(jù)庫提供的最基本的功能凸郑。當數(shù)據(jù)庫中出現(xiàn)第一個進程時,總免不了要將數(shù)據(jù)從磁盤上加載到內(nèi)存中,一次數(shù)據(jù)庫的物理I/O由此發(fā)生速兔。而這對應著數(shù)據(jù)庫的讀事件坛怪。通常大多數(shù)情況下淤齐,數(shù)據(jù)庫中不僅會伴隨著大量的讀,也會產(chǎn)生大量的寫入更新操作袜匿,而類似寫入更新的操作則需要將修改后的數(shù)據(jù)寫回到磁盤中更啄。
顯然,對于讀操作來說居灯,總是依據(jù)需要讀取數(shù)據(jù)的請求從磁盤上或內(nèi)存中找到對應滿足的數(shù)據(jù)返回給客戶端祭务。也就是說,讀操作必定是伴隨著客戶端會話的請求而出現(xiàn)的怪嫌。那么义锥,寫操作在數(shù)據(jù)被更新/修改后是如何寫回到磁盤中的?
Oracle實例在啟動時在內(nèi)存中劃分了一塊區(qū)域岩灭,被稱作 SGA(System Global Area,系統(tǒng)全局區(qū))
拌倍。其中共有6大內(nèi)存區(qū)域,緩沖數(shù)據(jù)庫中的數(shù)據(jù)部分的內(nèi)存區(qū)域則稱為 Database Buffer Cache(數(shù)據(jù)庫高速緩存區(qū))
噪径。
Database Buffer Cache
主要用來提高數(shù)據(jù)的訪問性能柱恤,避免訪問數(shù)據(jù)庫過程中出現(xiàn)大量的磁盤讀寫≌野可見梗顺,Database Buffer Cache 存在的意義不僅在于緩存數(shù)據(jù)庫中讀的數(shù)據(jù),而且需要提升數(shù)據(jù)庫的寫性能车摄。既然如此荚守,數(shù)據(jù)被修改或更新后也不是立刻會寫回到磁盤中的,而應該有一定的規(guī)則將數(shù)據(jù)緩存區(qū)中的數(shù)據(jù)寫回到磁盤中练般。而實現(xiàn)這一機制的矗漾,則是 DBWR(Database Writer)
。
后臺進程-DBWR
DBWR
是Oracle數(shù)據(jù)庫中的一個后臺進程薄料,用于將 Database Buffer Cache
中的被修改的數(shù)據(jù)寫回到磁盤中敞贡。在數(shù)據(jù)庫中,數(shù)據(jù)最先從磁盤上讀取數(shù)據(jù)并加載到內(nèi)存中摄职,此時的數(shù)據(jù)并沒有被任何的用戶進程修改過誊役,這種類型的數(shù)據(jù)稱為 Cleaning Data
获列。而當數(shù)據(jù)庫中的數(shù)據(jù)被用戶進程修改了某些字段的值后,因為數(shù)據(jù)是在內(nèi)存中被修改的蛔垢,修改后的數(shù)據(jù)(內(nèi)存中)因為與磁盤上的數(shù)據(jù)文件中記錄的數(shù)據(jù)已經(jīng)發(fā)生了不同击孩,因此這部分被修改過的數(shù)據(jù)被稱為 Dirty Data
。當內(nèi)存區(qū)域中的 Dirty Data 被 DBWR 進程寫入到磁盤上后鹏漆,數(shù)據(jù)文件又恢復 Clenaing
狀態(tài)巩梢,這個過程稱為 刷臟
。
內(nèi)存中的數(shù)據(jù)是無論如何也要寫回到磁盤中的艺玲,這一點是確定無疑的括蝠。但更困難的問題在于以什么樣的機制將數(shù)據(jù)寫回到磁盤。
針對這個問題饭聚,或許有很多中解決方案忌警。或者寫入發(fā)生在數(shù)據(jù)修改的那一刻秒梳,或者定時定量將數(shù)據(jù)寫回到磁盤法绵,或者由其他機制(進程)觸發(fā)寫入操作,或許都是可行的方案酪碘。
先說說寫入發(fā)生在數(shù)據(jù)修改的那一刻的情況朋譬,這種情況下數(shù)據(jù)庫中發(fā)生一次數(shù)據(jù)修改后,就需要立刻將數(shù)據(jù)寫回到磁盤中婆跑。顯然,一旦這么做會在數(shù)據(jù)庫中產(chǎn)生大量的物理寫入庭呜,而過多的物理I/O會降低數(shù)據(jù)庫的性能滑进,顯然,修改即寫入無法滿足數(shù)據(jù)庫的性能要求募谎,但這種方式或許是保障數(shù)據(jù)不會丟失的好辦法扶关。
接著是定時定量將內(nèi)存中的數(shù)據(jù)寫回到磁盤中,這種方式也是 DBWR
機制中的一種数冬。與修改即寫入不同的是节槐,被修改的數(shù)據(jù)會在內(nèi)存中保留一段時間,直到達到數(shù)據(jù)庫后臺進程 DBWR 設定(默認)的時間閾值后拐纱,一次將內(nèi)存中被修改的數(shù)據(jù)塊寫回到磁盤中铜异。相比修改即寫入,定時定量將內(nèi)存區(qū)域被修改的數(shù)據(jù)塊則可以避免可能發(fā)生在數(shù)據(jù)庫中的大量物理I/O問題秸架,從而提高數(shù)據(jù)庫的訪問性能揍庄。
DBWR 后臺進程中也是定時定量對 數(shù)據(jù)庫高速緩存區(qū) 中的數(shù)據(jù)進行寫回到磁盤操作的。在Oracle中东抹,DBWR 每隔3s啟動一次進程將數(shù)據(jù)寫回到磁盤中蚂子;另一種情況是當內(nèi)存中的臟數(shù)據(jù)塊占比達到一定限制后沃测,也會觸發(fā) DBWR 進程將臟數(shù)據(jù)刷回到磁盤中去。
再來說按規(guī)則(機制)將內(nèi)存中的數(shù)據(jù)寫回到磁盤的情況食茎。這種方式類似于定時定量的方式蒂破,都是以某一種設定條件作為觸發(fā) DBWR 寫數(shù)據(jù)的依據(jù)。在Oracle中别渔,則是使用 CKPT
檢查點作為觸發(fā) DBWR 的條件附迷。
當數(shù)據(jù)庫發(fā)生檢查點事件時,后臺進程 DBWR 會被啟動钠糊,并將當前內(nèi)存區(qū)域中的臟數(shù)據(jù)統(tǒng)一寫回到磁盤中的數(shù)據(jù)文件挟秤。數(shù)據(jù)中的檢查點回周期性的執(zhí)行,以此保證內(nèi)存中的數(shù)據(jù)可以有效的被寫回磁盤抄伍。
后臺進程-LGWR
數(shù)據(jù)庫中 DBWR 進程觸發(fā)時艘刚,會響應啟動另一個后臺進程-LGWR
,用于將數(shù)據(jù)庫中數(shù)據(jù)變更的歷史記錄到日志文件中截珍。并且攀甚,DBWR 后臺進程在 LGWR 進程寫入重做日志期間會保持阻塞狀態(tài),當 LGWR 寫入日志完成后岗喉,DBWR 開始將內(nèi)存中的數(shù)據(jù)寫入到磁盤中秋度。
在 SGA
內(nèi)存區(qū)中,保存重做日志的區(qū)域稱為 Redo Log Buffer(重做日志緩存區(qū))
钱床,當需要將數(shù)據(jù)修改對應的日志記錄到日志文件中時荚斯,會觸發(fā) LGWR 后臺進程將緩存區(qū)的日志寫入到重做日志文件中。
在Oracle數(shù)據(jù)庫中查牌,日志的完整性是十分重要的事期。絕不僅僅只是記錄,當實例異常故障后再恢復時需要應用重做日志文件纸颜,將數(shù)據(jù)庫恢復到故障前一刻的狀態(tài)兽泣。只有被寫入重做日志中的數(shù)據(jù),在內(nèi)存區(qū)域被修改的數(shù)據(jù)才算是安全的胁孙。
與數(shù)據(jù)何時寫回到磁盤一樣唠倦,數(shù)據(jù)庫日志緩存區(qū)的日志也需要根據(jù)一定的規(guī)則將日志文件記錄到重做日志文件中。觸發(fā) LGWR 進程寫入日志的情況包含以下幾種:
當用戶進程執(zhí)行了 rollback(回滾)
或 commit(提交)
事件時涮较,數(shù)據(jù)庫會啟動后臺的 LGWR 進程稠鼻,將相應的數(shù)據(jù)變更的記錄記錄到聯(lián)機重做日志文件中;同樣狂票,當內(nèi)存區(qū)域的日志緩存區(qū)的空間不夠用時枷餐,也會觸發(fā) LGWR 后臺進程將日志緩存區(qū)的日志寫入到重做日志中。
與 DBWR 一樣,LGWR 也會每隔3s將日志緩存區(qū)的日志寫入到重做日志中毛肋。
redo log buffer 內(nèi)存區(qū)域的日志占用的空間達到一定限制后(默認超過日志緩存區(qū)1/3的空間時)怨咪,觸發(fā) LGWR 后臺進程開始將緩存區(qū)的日志寫入到重做日志中。
最后润匙,LGWR 寫日志時會根據(jù)日志出現(xiàn)的先后順序?qū)?nèi)存區(qū)域的日志順序的寫入到日志文件中诗眨,是為了數(shù)據(jù)庫恢復時按照數(shù)據(jù)被修改的先后順序應用redo,保證數(shù)據(jù)的正確性和一致性孕讳。