oracle深度解析檢查點(diǎn)
由于中LGWR和DBWR工作的不一致,Oracle引入了檢查點(diǎn)的概念,用于同步,保證數(shù)據(jù)庫(kù)的一致性。在Oracle里面,檢查點(diǎn)分為兩種:完全檢查點(diǎn)和增量檢查點(diǎn)。下面我們分別介紹這兩種檢查點(diǎn)的作用:
1、完全檢查點(diǎn)
在Oracle8i之前,數(shù)據(jù)庫(kù)的發(fā)生的檢查點(diǎn)都是完全檢查點(diǎn),完全檢查點(diǎn)會(huì)將數(shù)據(jù)緩沖區(qū)里面所有的臟數(shù)據(jù)塊寫入相應(yīng)的數(shù)據(jù)文件中,并且同步數(shù)據(jù)文件頭和控制文件,保證數(shù)據(jù)庫(kù)的一致。完全檢查點(diǎn)在8i之后只有在下列兩種情況下才會(huì)發(fā)生:
(1)DBA手工執(zhí)行alter system checkpoint的命令;
(2)數(shù)據(jù)庫(kù)正常shutdown(immediate,transcational,normal)。
由于完全檢查點(diǎn)會(huì)將所有的臟數(shù)據(jù)庫(kù)塊寫入,巨大的IO往往會(huì)影響到數(shù)據(jù)庫(kù)的性能。因此Oracle從8i開(kāi)始引入了增量檢查點(diǎn)的概念。
2、增量檢查點(diǎn)
Oracle 從8i開(kāi)始引入了檢查點(diǎn)隊(duì)列這么一種概念,用于記錄數(shù)據(jù)庫(kù)里面當(dāng)前所有的臟數(shù)據(jù)塊的信息,DBWR 根據(jù)這個(gè)隊(duì)列而將臟數(shù)據(jù)塊寫入到數(shù)據(jù)文件中。檢查點(diǎn)隊(duì)列按時(shí)間先后記錄著數(shù)據(jù)庫(kù)里面臟數(shù)據(jù)塊的信息,里面的條目包含RBA(Redo Block Address,重做日志里面用于標(biāo)識(shí)檢查點(diǎn)期間數(shù)據(jù)塊在重做日志里面第一次發(fā)生更改的編號(hào))和數(shù)據(jù)塊的數(shù)據(jù)文件號(hào)和塊號(hào)。在檢查點(diǎn)期間不論數(shù)據(jù)塊更改幾次,它在檢查點(diǎn)隊(duì)列里面的位置始終保持不變,檢查點(diǎn)隊(duì)列也只會(huì)記錄它最早的RBA,從而保證最早更改的數(shù)據(jù)塊能夠盡快寫入。當(dāng)DBWR將檢查點(diǎn)隊(duì)列里面的臟數(shù)據(jù)塊寫入到數(shù)據(jù)文件后,檢查點(diǎn)的位置也要相應(yīng)地往后移,CKPT每三秒會(huì)在控制文件中記錄檢查點(diǎn)的位置,以表示Instance Recovery時(shí)開(kāi)始恢復(fù)的日志條目,這個(gè)概念稱為檢查點(diǎn)的“心跳”(heartbeat)。檢查點(diǎn)位置發(fā)生變更后,Oracle里面通過(guò)4個(gè)參數(shù)用于控制檢查點(diǎn)位置和最后的重做日志條目之間的距離。在這里面需要指出的是,多數(shù)人會(huì)將這4個(gè)參數(shù)看作控制增量檢查點(diǎn)發(fā)生的時(shí)間。事實(shí)上這是錯(cuò)誤的,這4個(gè)參數(shù)是用于控制檢查點(diǎn)隊(duì)列里面的條目數(shù)量,而不是控制檢查點(diǎn)的發(fā)生。
(1)fast_start_io_target
該參數(shù)用于表示數(shù)據(jù)庫(kù)發(fā)生Instance Recovery的時(shí)候需要產(chǎn)生的IO總數(shù),它通過(guò)v$filestat的AVGIOTIM來(lái)估算的。比如我們一個(gè)數(shù)據(jù)庫(kù)在發(fā)生Instance Crash后需要在10分鐘內(nèi)恢復(fù)完畢,假定OS的IO每秒為500個(gè),那么這個(gè)數(shù)據(jù)庫(kù)發(fā)生Instance Recovery的時(shí)候大概將產(chǎn)生500*10*60=30,000次IO,也就是我們將可以把fast_start_io_target設(shè)置為 30000。
(2)fast_start_mttr_target
我們從上面可以看到fast_start_io_target 來(lái)估算檢查點(diǎn)位置比較麻煩。Oracle為了簡(jiǎn)化這個(gè)概念,從9i開(kāi)始引入了 fast_start_mttr_target這么一個(gè)參數(shù),用于表示數(shù)據(jù)庫(kù)發(fā)生Instance Recovery的時(shí)間,以秒為單位。這個(gè)參數(shù)我們從字面上也比較好理解,其中的mttr是mean time to recovery的簡(jiǎn)寫,如上例中的情況我們可以將fast_start_mttr_target設(shè)置為600。當(dāng)設(shè)置了 fast_start_mttr_target后,fast_start_io_target這個(gè)參數(shù)將不再生效,從9i后 fast_start_io_target這個(gè)參數(shù)被Oracle廢除了。
(3)log_checkpoint_timeout
該參數(shù)用于表示檢查點(diǎn)位置和重做日志文件末尾之間的時(shí)間間隔,以秒為單位,默認(rèn)情況下是1800秒。
(4)log_checkpoint_interval
該參數(shù)是表示檢查點(diǎn)位置和重做日志末尾的重做日志塊的數(shù)量,以O(shè)S塊表示。
(5)90% OF SMALLEST REDO LOG
除了以上4個(gè)初始化參數(shù)外,Oracle內(nèi)部事實(shí)上還將重做日志文件末尾前面90%的位置設(shè)為檢查點(diǎn)位置。在每個(gè)重做日志中,這么幾個(gè)參數(shù)指定的位置可能不盡相同,Oracle將離日志文件末尾最近的那個(gè)位置確認(rèn)為檢查點(diǎn)位置。
oracle 9i instance recovery
1、增量檢查點(diǎn)
在checkpoint queue的基礎(chǔ)上實(shí)現(xiàn)了增量檢查點(diǎn),每3秒發(fā)生一次checkpoint heartbeat,記錄dbwr上次寫成功的最大RBA(redo block address)。這樣的話做instance recovery的時(shí)候就從這個(gè)rba開(kāi)始,而不是從上次checkpoint scn開(kāi)始,大大節(jié)省了恢復(fù)時(shí)間。
2、twice scan of redo log
在應(yīng)用redo之前,redo將會(huì)被操作兩次,第一次去掃描哪些redo record需要被應(yīng)用,因?yàn)?i在redo里添加了dbwr寫數(shù)據(jù)塊的信息,所以dbwr發(fā)生前的日志將不會(huì)被應(yīng)用。第二步就是選出需要被應(yīng)用的日志然后開(kāi)始rollforward。
3、rollforward
在做instance recovery時(shí)必須先定位到redo log 然后應(yīng)用所有日志到datafile,這時(shí)候包括了committed和uncommitted的數(shù)據(jù)。當(dāng)做完rollward,數(shù)據(jù)庫(kù)就可以open了。
4、rollback
因 為rollforward產(chǎn)生了uncommitted數(shù)據(jù),所以必須回滾這些數(shù)據(jù)。這將由smon和on-demand rollback來(lái)實(shí)現(xiàn)。smon將會(huì)掃描undo segment header去標(biāo)志所有活動(dòng)事務(wù)為dead,然后會(huì)逐漸去回滾這些事務(wù)。另外on-demand rollback提供了前臺(tái)進(jìn)程進(jìn)行rollback,當(dāng)前臺(tái)進(jìn)程企圖獲得被dead事務(wù)占用row lock,這時(shí)候前臺(tái)進(jìn)程將會(huì)去undo segment取得before image去回滾這個(gè)塊,至于其他被這個(gè)dead事務(wù)lock的塊就等待smon去回滾。
另外,如果 在數(shù)據(jù)庫(kù)打開(kāi)的過(guò)程中process crash導(dǎo)致transaction dead,resource不能被釋放的情況,這時(shí)候如果另一個(gè)進(jìn)程需要這些resource,那么這個(gè)進(jìn)程將會(huì)等待直到pmon清理dead process釋放出resource。
如果數(shù)據(jù)庫(kù)Crash,重新啟動(dòng),很久遠(yuǎn)以前的未提交事務(wù)并不在Redo的恢復(fù)序列中。
但是未提交事務(wù)一定在回滾段事務(wù)表上存在,并且State=10,為活動(dòng)事務(wù)。這就夠了。
數(shù)據(jù)庫(kù)啟動(dòng)之后,這些事務(wù)會(huì)被SMON逐個(gè)標(biāo)記為Dead(不可能再活過(guò)來(lái)了),然后由SMON慢慢去回滾這些事務(wù);也存在另外一種情況,后來(lái)的進(jìn)程會(huì)去讀這些未提交數(shù)據(jù),發(fā)現(xiàn)Dead事務(wù)未提交,則主動(dòng)進(jìn)行回滾。
1、一個(gè)數(shù)據(jù)塊發(fā)生更新,必然寫回滾
2、回滾段的block變化也記錄在redo中
一份未提交的數(shù)據(jù)必定在回滾中有相應(yīng)的前鏡像,任何正常的恢復(fù)都一定會(huì)把這些變化重新構(gòu)建出來(lái)。
想像一下
1、update事務(wù)1更新了block 1
2、回滾段1記錄了block1的前鏡像
3、checkpoint
4、update事務(wù)2更新了block2
5、回滾段2記錄了block2的前鏡像
6、instance crash
現(xiàn)在重啟數(shù)據(jù)庫(kù)
1、根據(jù)redo重新構(gòu)建block2
2、根據(jù)redo重新構(gòu)建回滾段2
3、database open
4、SMON用回滾段2的數(shù)據(jù)回滾block2,SMON用回滾段1的數(shù)據(jù)回滾block1
最后一步也可能是
在另外一個(gè)select檢索到block1或者block2的時(shí)候,發(fā)現(xiàn)這兩個(gè)block的數(shù)據(jù)都是未提交的,此時(shí)再回滾block1和block2。
所以,只要有相應(yīng)的回滾數(shù)據(jù)存在,無(wú)論什么時(shí)候oracle都可以找到一致的數(shù)據(jù),oracle只需要知道這個(gè)事務(wù)是提交了的還是沒(méi)提交了的,而這點(diǎn)在block header ITL中有記錄。
posted on 2011-11-30 11:00 順其自然EVO 閱讀(1791) 評(píng)論(0) 編輯 收藏