redo/undo
一、什么是redo?
redo:oracle在在線或者歸檔重做日志文件中的記錄的信息,外以出現失敗時可以利用這些數據來"重放"事務。
每個oracle數據都至少有二個在線重做日志組,每個組中的至少有一個成員,這些在線重做日志組以循環方式使用。
二、什么是undo?
undo:oracle在undo段中記錄的信息,用于取消或者回滾事務。
undo在數據庫內部存儲在一組特殊的段中,稱作undo段。
利用undo段恢復數據,不是將數據庫物理地恢復到執行語句或者事務之前的樣子,只是從邏輯上恢復到原來的樣子,但是數據結構以及數據庫塊本身在回滾后可能大不相同。oracle在回滾時候,它實際上會做與先前邏輯上相反的工作,對于每個insert,oracle會完成一個delete,對于每個delete,oracle會執行一個insert,對于每個update,oracle則會執行一個"反update",或者執行另外一個update,將修改前的行放回去。
小實驗:
create table t as select * from all_objects where 1=0;
select * from t;
set autotrace traceonly statistics
select * from t;
insert into t select * from all_objects;
rollback;
select * from t;
set autotrace traceonly statistics
select * from t;
三、redo和undo如何協作?
undo信息存儲在undo表空間或者undo段中,但是也會受到redo的保護。
在dml語句中,redo和undo都會生成。update生成的undo要比insert大,因為update需要保存修改數據的"前"映像。
系統崩潰恢復有兩個過程,首先數據前滾,把系統放到失敗點上,然后回滾尚未提交的所有工作。這個動作會再次同步數據文件。它會重放已經進行的工作,并撤銷尚未完成的所有工作。
oracle有一點很重要:rollback過程從不涉及到redo日志。只有恢復和歸檔時會讀取redo日志。oracle的目標是可以順序寫redo日志,而且在寫日志時別人不會讀日志 。
四、commit會做什么?
commit通常是一個非常快的操作,而不論事務大小如何。
這是oracle提倡用戶的使用事務的提交根據業務來原因之一。commit的開銷存在二個因素:
1、增加與數據庫的往返通信。
2、每次提交時,必須等待redo寫至磁盤,這會導致"等待"。在這種情況下,等待稱為"log file sync".
commit前做的工作:
1、已經在SGA中生成了undo塊。
2、已經在SGA中生成了已經修改數據塊。
3、已經在SGA中生成了對應前二項的緩存redo。
4、取決于前三項的大小,以及這些工作花費的時間,前面的某個數據或者某些數據可能已經刷新輸出到磁盤。
5、已經得到了所需的全部鎖。
commit時候做的工作:
1、為事務生成一個scn。每次有人commit時,scn都會增1。
2、lgwr將所有余下的緩存重做日志條目寫至磁盤,并把scn記錄到redo日志文件中。這一步是真正的commit。如果出現了這一步,即已經提交。事務條目會從v$transaction中刪除,這說明我們已經提交。
3、v$lock中記錄著我們的會話持有的鎖,這些鎖都將被釋放,而排隊等待這些鎖的每一個人都會喚醒,可以繼續完成他們的工作。
4、如果事務修改的某些塊還在緩沖區緩存中,則會以一種快速的模式訪問并"清理"。塊清除是指清除存儲在數據塊首部的與鎖相關的信息。
五、rollback會做什么?
rollback必須邏輯地撤銷我們所做的工作,回滾時間絕對是所修改數據量的一個函數。
rollback時候做的工作:
1、撤銷已經做的所有修改。其完成方式如下:從undo段讀回數據,然后實際上逆向執行前面所做的操作,并將undo條目標記為已用。
2、會話持有的所有鎖都將釋放,如果有人在排隊等待我們持有的鎖,就會被喚醒。
六、分析redo
redo管理是數據庫中的一個串行點。任何oracle實例都只有一個lgwr,最終所有事務都會歸于lgwr,要求這個進程管理他們的redo,并commit其事務。lgwr要做的越多,系統就會越慢。
1、如何測量redo?
v$mystat:會話的統計信息。
v$statname:這個視圖告訴我們v$mystat中的每一行代表什么意思。
select b.NAME,a.VALUE from v$mystat a,v$statname b where a.STATISTIC#=b.STATISTIC# and b.name='redo size';
七、redo生成和before/after觸發器。
1、before或者after觸發器不影響delete生成的redo。
2、oracle9i release 2以及以前版本中,before或者after觸發器會使insert生成同樣數量的額外redo。在oracle 10g中,則不會生成任何額外的redo。
3、在oracle9i release 2 及以前的所有版本中,update生成的redo只受before觸發器影響,after觸發器不會增加任何額外的redo,不過oracle 10g中,
如果一個表沒有觸發器,對其更新期間生成的redo量總是比oracle9i及以前版本中要少。看來這是oracle著力解決的一個關鍵問題:對于無觸發器的表,要減少這種表更新所生成的redo量。
在oracle 10g中,如果表有一個before觸發器,則其更新期間生成的redo量比9i中更大。
如果表中after觸發器,則更新所生成的redo量與9i中一樣。
每個開發人員應該具備的能力:
1、估計你的"事務"大小(需要修改數據量)。
2、在修改的數據量基礎上再增加10%-20%的開銷,具體增加多大的開銷取決于你的要修改的行數,修改得行數越多,增加的開銷就越小。
3、對于update,要把這個估計值加倍。八、我能關掉redo日志生成嗎?
答案:不能。
1、在sql中設置nologging:有些sql和操作支持nologging字句,這個對象的所有操作在執行時都不生成重做日志,而是說有些特定操作生成的redo會比平常少的多。
select * from v$database;
--改成archivelog mode
shutdown immediate
startup mount
alter database archivelog;
alter database open;
--改成noarchivelog mode
shutdown immediate
startup mount
alter database noarchivelog;
alter database open;
----------------------------------
drop table t;
@ 'C:\Oracle\mystat' "redo size"
create table t as select * from all_objects;
@ 'C:\Oracle\mystat' "redo size"
drop table t;
@ 'C:\Oracle\mystat' "redo size"
create table t nologging as select * from all_objects;
@ 'C:\Oracle\mystat' "redo size"
在noarchiving mode的數據庫中,除了數據字典的修改外,create table不會記錄日志,create index/drop index生成日志。
關于nologging操作,需要注意地方:
雖然是nologging mode,還會生成少量的redo,這些redo作用是保護數據字典。
nologging不能避免所有后續操作生成redo,在前面例子中,dml操作還會正常生成redo日志,sql*loader、insert /*append*/語法不生成日志。
在一個archivelog模式的數據執行nologging操作后,必須盡快為受影響的數據文件建立一個新的基準備份,從而避免由于介質失敗而丟失對這些對象的后續修改。
2、nologing小結:
索引的創建和alter(rebuild)。
表的批量insert(通過/*append*/)或者采用sql*loader,表數據不生成redo。
lob操作。
通過create table as select 創建表。
各種alter table 操作。
在一個archiveing mode數據庫中適當使用nologging,可以加快許多操作的速度。
九、為什么不能分配一個新日志?
dbwr、lgwr、arch進程操作時異步,如果dbwr還沒有完成redo日志所保護數據的檢查點,或者arch還沒有把rdo日志文件復制到歸檔目標,就發生checkpoint not complete或者archival required。
解決辦法:
1、讓dbwr更快一些,可以使用async i/o、使用dbwr i/o從屬進程,或者使用多個dbwr進程。這個方法好處是:寧可ibuyong付出什么代價就能有所收獲,性能提高,而且不必修改如何邏輯/結構/代碼。
2、增加更多重做日志文件。這種方法:可以消除系統中的"暫停",其缺點是會消耗更多的磁盤空間。
3、重新創建更大的日志文件。
4、讓檢查點發生得更頻繁,此方法很不可取。
十、塊清除。
block cleanout:即刪除所有修改數據塊上與"鎖定"有關的信息。
有二個場合會做block cleanout,在commit時候,在SGA中的數據塊中"鎖定"信息會被清除掉,不在SGA中的數據塊的將被忽略;這些被忽略的塊會在第一次訪問時候被清除。
十一、日志競爭
出現日志競爭時,數據庫會提示“cannot allocate new log”。
原因可能是:redo放在一個慢速設備上。
redo與其他頻繁訪問的文件放在一個設備上。
以緩沖方式裝載日志設備。
redo采用一個慢速技術,比如RAID-5.
解決方法:每組的redo日志文件放在不同的磁盤上;使用快速的設備;以raw磁盤裝載日志。
十二、臨時表和redo/undo
臨時表不會為它們的塊生成redo。因此,對臨時表的操作不是“可恢復的”,修改臨時表中的一個塊時,不會將這個這個修改記錄到重做日志文件中,不過,臨時表確實會生成undo,而這個undo會記入日志,因此,臨時表也會生成一些redo。
臨時表的作用一般是insert和select為主。
十三、分析undo
1、dml操作生成undo情況
一般來說,insert生成的undo最少,因為oracle為此所需要記錄的只是要“delete”的一個rowid;update一般排名第二,對于update,只需記錄修改的字節;delete一般生成的redo最多,對于delete,oracle必須把整行的前映像記錄到undo段中。
如何測量?
在事務中,可以通過v$transaction.used_ublk字段察看。
drop table t;
create table t as select object_name unindexed,object_name indexed from all_objects ;
create index t_inx on t(indexed);
exec dbms_stats.gather_table_stats(user,'T');
SELECT used_ublk from v$transaction where addr =(select taddr from v$session where sid=(select sid from v$mystat where rownum=1));
update t set unindexed=lower(unindexed) ;
update t set indexed=lower(indexed);
2、ORA-01555:snapshot too old 錯誤
錯誤原因:undo段太小,不足以在系統上執行工作;你的程序跨commit獲取;塊清除。
解決方案:適當地設置參數undo_retention(要大于執行查詢嘴上的事務所需的時間),可以用v$undostat來確定長時間運行的查詢的持續時間,另外,要確保磁盤上已經預留了足夠的空間,使undo段能根據所請求的undo_retention增大。
使用手動的undo管理時加大或者增加更多的回滾段。這樣在長時間運行的查詢執行期間,覆蓋undo數據的可能性降低。
減少查詢的運行時間(調優)。
收集相關對象的停機信息,這個有助避免塊清除導致的錯誤。
3、undo段大小確定
undo段管理方法:
自動undo管理:通過undo_retention參數告訴oracle要把undo段保留多少時間。oralce根據并發工作負載來確定要創建多少個undo段,以及每個undo段應該多大,這個undo管理的推薦方法。
手動undo管理:dba根據估計和觀察到工作負載,確定手動的創建多少個undo段,dba根據事務量和長時間運行查詢的長度來確定這些undo段應該多大。(問題:控制的參數有多少?)
在手動undo管理中,undo段不會因為查詢而擴大,只有insert、update和delete才會讓undo段增長。所以dba需要定時調整undo段的大小。
在手動undo管理中,回收機制是首先回收最小的undo段,如果所有的undo段的大小相同,會回收最老的undo段。因此遇到ora-01555錯誤可能是系統中最小的回滾段指示的,就算你增加一個大的undo段也不能解決此問題,故建議設置一致的undo段大小。
4、延遲塊清除
在塊清除過程中,如果一個塊已經修改,下一個會話訪問這個塊時,可能必須查看最后一個修改這個塊的事務是否還是活動。一旦確定該事務不再活動,就會完成塊清除,這樣另外一個會話訪問這個塊時就不必再經歷同樣的過程。要完成塊清除,oracle會從塊首部確定前一個事務所用的undo段,然后確定從undo首部能不能看出這個事務很久以前就已經提交,它在undo段事務表中的事務槽以及被覆蓋,另一種情況是commit scn孩子undo段的事務表中,這說明該事務只是剛剛提交。
轉載于:https://www.cnblogs.com/luoyx/archive/2011/12/22/2298669.html
總結
- 上一篇: 有关WriteableBitmap和Bi
- 下一篇: 将CSDN600W用户及密码帐号存入本地