Oracle的REDO和UNDO
在這里會介紹UNDO,REDO是如何產生的,對TRANSACTIONS的影響,以及他們之間如何協同工作的。?
什么是REDO?
REDO記錄transaction logs,分為online和archived。以恢復為目的。?比如,機器停電,那么在重起之后需要online redo logs去恢復系統到失敗點。?比如,磁盤壞了,需要用archived redo logs和online redo logs區恢復數據。?比如,truncate一個表或其他的操作,想恢復到之前的狀態,同樣也需要。?
什么是UNDO?
REDO是為了重新實現你的操作,而UNDO相反,是為了撤銷你做的操作,比如你得一個TRANSACTION執行失敗了或你自己后悔了,則需要用ROLLBACK命令回退到操作之前。回滾是在邏輯層面實現而不是物理層面,因為在一個多用戶系統中,數據結構,blocks等都在時時變化,比如我們INSERT一個數據,表的空間不夠,擴展了一個新的EXTENT,我們的數據保存在這新的EXTENT里,其它用戶隨后也在這EXTENT里插入了數據,而此時我想ROLLBACK,那么顯然物理上講這EXTENT撤銷是不可能的,因為這么做會影響其他用戶的操作。所以,ROLLBACK是邏輯上回滾,比如對INSERT來說,那么ROLLBACK就是DELETE了。?
COMMIT 以前,常想當然地認為,一個大的TRANSACTION(比如大批量地INSERT數據)的COMMIT會花費時間比短的TRANSACTION長。而事實上是沒有什么區別的,?
因為ORACLE在COMMIT之前已經把該寫的東西寫到DISK中了,?
我們COMMIT只是?
1,產生一個SCN給我們TRANSACTION,SCN簡單理解就是給TRANSACTION排隊,以便恢復和保持一致性。?
2,REDO寫REDO到DISK中(LGWR,這就是log file sync),記錄SCN在ONLINE REDO LOG,當這一步發生時,我們可以說事實上已經提交了,這個TRANSACTION已經結束(在V$TRANSACTION里消失了)?
3,SESSION所擁有的LOCK(V$LOCK)被釋放。?
4,Block Cleanout(這個問題是產生ORA-01555: snapshot too old的根本原因) ROLLBACK ROLLBACK和COMMIT正好相反,ROLLBACK的時間和TRANSACTION的大小有直接關系。因為ROLLBACK必須物理上恢復數據。COMMIT之所以快,是因為ORACLE在COMMIT之前已經作了很多工作(產生UNDO,修改BLOCK,REDO,LATCH分配),?
ROLLBACK慢也是基于相同的原因。?
ROLLBACK會?
1,恢復數據,DELETE的就重新INSERT,INSERT的就重新DELETE,UPDATE的就再UPDATE。?
2,RELEASE LOCK ROLLBACK要比COMMIT消耗更多資源,因為ORACLE認為你一旦做數據更新,那么就意味著你要COMMIT(其他數據庫不全是這種設計理念,比如DB2),所以在你更新數據的時候就做了大量的工作,這也可以理解為什么不建議用TABLE來做TEMPORARY TABLE。(TEMP TABLE消耗的REDO比固定表在INSERT時要少很多 ,UPDATE時差不多是1/2,?
但是DELETE卻相差無幾) REDO 產生REDO 越多,你的系統越慢,不但影響你自己的SESSION,還影響其他SESSION,LGWR管理REDO,并且是TRANSACTION的結束標志。?
首先要知道怎么監控REDO,當然,SET AUTOTRACE ON可以,不過只能監控DML語句,而像PROCEDURE則無法監視。那么我們就需要觀察字典了,V$MYSTAT, V$STATNAME,?
前面有兩個腳本,mystat,mystat2
Sql代碼 ?
看到APPEND插入用了11,912字節的REDO,比一般性插入要少很多。或者用這個PROCEDURE也可以觀察SQL消耗的REDO.
Java代碼 ?
?用法就不多說了。 減少REDO 既然REDO這么消耗資源,那我們能屏蔽REDO嗎?顯然不能,那我們能減少REDO嗎?這是可以的(注意,9.2以后,可以用FORCE LOGGING開關來控制是否強制REDO,如果YES,則不管NOLOGGING還是APPEND都是不起任何作用的,可以SELECT FORCE_LOGGING FROM V$DATABASE查看是否FORCE。另外需要明白,沒有一個辦法能徹底不記錄REDO,只能是減少REDO。因為不管如何,數據字典總是要產生一些REDO的。 create table nologging as select xxx新建的表沒有原來表的索引和默認值,只有非空(not null)的約束素條件可以繼承過來. INSERT /*+ APPEND */ INTO target_tablename SELECT 如果運行此命令時還有對target_tablename的DML操作會排隊在它后面,對OLTP系統在用的表操作是不合適的。快速插入數據可以指定append提示,但是需要注意 noarchivelog模式下,默認用了append就是nologging模式的。 在archivelog下,需要把表設置程Nologging模式。可以通過如下語句設置為NO FORCE LOGGING。 Alter database no force logging; 這兩種方法轉移數據時沒有用SGA里數據緩沖區和事物處理的回滾段, 也不寫聯機事物日志,就象數據庫裝載工具SQLLOAD一樣直接把數據寫到物理文件。 REDO的問題?
有時,會在ALERT中發現?
Thread 1 cannot allocate new log, sequence 1466 Checkpoint not complete Current log# 3 seq# 1465 mem# 0: /home/ora10g/oradata/ora10g/redo03.log?
這問題出現在系統嘗試reuse online redo log file但是卻沒有可用的。可能是由于DBWR沒有完成(Checkpoint not complete)或ARCH沒有完成。?
1,DBWR,用多DBWR process,合理分布數據,?
2,增加REDO LOG FILE?
3,擴大REDO的大小?
4,讓CHECKPOINT發生更頻繁,可以減少block buffer cache,FAST_START_MTTR_TARGET, LOG_CHECKPOINT_INTERVAL,LOG_CHECKPOINT_TIMEOUT。?
?
轉載:http://blog.csdn.net/hdhai9451/archive/2009/02/27/3942051.aspx
二REDO和UNDO的區別
寫的次序:
redo--> undo-->datafile insert一條記錄時, 表跟undo的信息都會放進 redo 中, 在commit 或之前, redo 的信息會放進硬盤上. 故障時, redo 便可恢復那些已經commit 了的數據. redo->每次操作都先記錄到redo日志中,當出現實例故障(像斷電),導致數據未能更新到數據文件,則數據庫重啟時須redo,重新把數據更新到數據文件 undo->記錄更改前的一份copy,但你系統rollback時,把這份copy重新覆蓋到原來的數據 redo->記錄所有操作,用于恢復(redo records all the database transaction used for recovery) undo->記錄所有的前印象,用于回滾(undo is used to store uncommited data infor used for rollback) redo->已遞交的事務,實例恢復時要寫到數據文件去的 undo->未遞交的事務. redo的原因是:每次commit時,將數據的修改立即寫到online redo中,但是并不一定同時將該數據的修改寫到數據文件中。因為該數據已經提交,但是只存在聯機日志文件中,所以在恢復時需要將數據從聯機日志文件中找出來,重新應用一下,使已經更改數據在數據文件中也改過來!
undo的原因是:在oracle正常運行時,為了提高效率,加入用戶還沒有commit,但是空閑內存不多時,會由DBWR進程將臟塊寫入到數據文件中,以便騰出寶貴的內存供其它進程使用。這就是需要UNDO的原因。因為還沒有發出commit語句,但是oracle的dbwr進程已經將沒有提交的數據寫到數據文件中去了。 undo 也是也是datafile, 可能dirty buffer 沒有寫回到磁盤里面去。只有先redo apply 成功了,才能保證undo datafile 里面的東西都是正確的,然后才能rollback 做undo的目的是使系統恢復到系統崩潰前(關機前)的狀態,再進行redo是保證系統的一致性. 不做undo,系統就不會知道之前的狀態,redo就無從談起 所以instance crash recovery 的時候總是先rollforward, 再rollback undo 回退段中的數據是以“回退條目”方式存儲。回退條目=塊信息(在事務中發生改動的塊的編號)+在事務提交前存儲在塊中的數據 在每一個回退段中oracle都為其維護一張“事務表” 在事務表中記錄著與該回退段中所有回退條目相關的事務編號(事務SCN&回退條目) redo 重做記錄由一組“變更向量”組成。每個變更變量中記錄了事務對數據庫中某個塊所做的修改。
當用戶提交一條commit語句時,LGWR進程會立刻將一條提交記錄寫入到重做日志文件中,然后再開始寫入與該事務相關的重做信息。 #事務提交成功后,Oracle將為該事備生成一個系統變更碼(SCN)。事務的SCN將同時記錄在它的提交記錄和重做記錄中。
commit 提交事務前完成的工作:
·在SGA區的回退緩存中生成該事務的回退條目。在回退條目中保存有該事務所修改的數據的原始版本。
·在SGA區的重做日志緩存中生成該事務的重做記錄。重做記錄中記載了該事務對數據塊所進行的修改,并且還記載了對回退段中的數據塊所進行的修改。緩存中的重做記錄有可能在事務提交之前就寫入硬盤中。
·在SGA區的數據庫緩豐中記錄了事務對數據庫所進行的修改。這些修改也有可能在事務提交之前就寫入硬盤中。
提交事務時完成的工作:
·在為該事務指定的回退段中的內部事務表內記錄下這個事務已經被提交,并且生成一個惟一的SCN記錄在內部事務表中,用于惟一標識這個事務。
·LGWR后進進程將SGA區重做日志緩存中的重做記錄寫入聯機重做日志文件。在寫入重做日志的同時還將寫入該事務的SCN。
·Oracle服務進程釋放事務所使用的所有記錄鎖與表鎖。
·Oracle通知用戶事務提交完成。
·Oracle將該事務標記為已完成。
?rollback 回退事務完成的工作:
·Oracle通過使用回退段中的回退條目,撤銷事務中所有SQL語句對數據庫所做的修改。
·Oracle服務進程釋放事務所使用的所有鎖
·Oracle通知事務回退成功。
·Oracle將該事務標記為已完成
舉個例子: insert into a(id) values(1);(redo) 這條記錄是需要回滾的。回滾的語句是delete from a where id = 1;(undo) 試想想看。如果沒有做insert into a(id) values(1);(redo) 那么delete from a where id = 1;(undo)這句話就沒有意義了。 現在看下正確的恢復: 先insert into a(id) values(1);(redo) 然后delete from a where id = 1;(undo) 系統就回到了原先的狀態,沒有這條記錄了。
?
總結
以上是生活随笔為你收集整理的Oracle的REDO和UNDO的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《终于有人说出来了——Java不适合于作
- 下一篇: 至毕业设计组同学的一封公开信