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