5、分析redo
redo的管理是資料庫的一個串行點,每個oracle資料庫執行個體都隻有一個LGWR程序,所有的事務都會要求LGWR程序去管理,寫他們的各自的redo,每個操作的LGWR寫的越多,就會使系統越慢。是以我們就要時刻關注每一個事務生成的rodo的量。
如何檢視redo的量呢? 你可能會想到用sql*plus内置的特性AUTOTRACE來檢視,但是有個問題Tom說這個特性隻能檢視比較簡單的DML語句,對于一些複雜的操作我們還是需要檢視兩個動态性能表:
V$MYSTAT: 其中有每個會話的送出的資訊。
V$STATNAME:這個視圖告訴我們V$MYSTAT視圖的每一行表示什麼
對于Oracle9i Release 2,DBA 可能把資料庫置于FORCE LOGGING 模式。在這種情況下,所有操作都會計入日志。查詢SELECT
FORCE_LOGGING FROM V$DATABASE 可以檢視是否強制為日志模式。這個特性是為了支援Data Guard, Data Guard 是Oracle 的一個災難恢複特性,它依賴于redo來維護一個備用資料庫(standby
database)備份。
在sql中設定nologing:
有些SQL 語句和操作支援使用NOLOGGING 子句。這并不是說:這個對象的所有操作在執行時都不生成重做日志,而是說有些特定操作生成的redo 會比平常(即不使用NOLOGGING 子句時)少得多。注意,我隻是說“redo”少得多,而不是“完全沒有redo“。所有操作都會生成一些redo——不論日志模式是什麼,有資料字典操作都會計入日志。隻不過使用NOLOGGING
子句後,生成的redo 量可能會顯著減少。
5.1 塊清除:
有時候我們在執行select操作的時候也可能會産生redo,其一個可能原因就是oracle塊清除。塊清除就是删除所修改資料塊上與"鎖定"有關的資訊,即事務資訊。Oracle在事務相關的送出清單中,記錄下已修改的塊清單,每個清單記錄20個塊,根據需要可能配置設定有多個這種清單。這種塊清單有一個上限,就是緩沖區緩存大小的10%.
如果一次修改的塊,沒有超過了緩沖區緩存大小的10%,并且這些塊在記憶體中,則commit時,會清除塊上的事務資訊,否則,就不會理會它,直到下次通路這些塊時,再清除塊中的事務資訊,這就是延遲塊清除.因為這個Select修改了塊的事務資訊,是以就會産生Redo.
塊清楚的分類:
fast commit cleanout 和 delayed block cleanout 這兩種:
如果一個事務修改的塊不超過資料緩沖區(data buffer catch)的10%,那麼oracle 做的是fast commit cleanout。
如果是一個事務修改的塊超過了10%,那麼oracle就執行delayed block cleanout,還有一種情況會執行delayed block cleanout,那就是當事務還沒有送出的時候,資料塊已經被重新整理輸出到了磁盤中,當執行commit的時候,oracle不會再把這個塊調入緩沖區來執行塊清除,而是把這個操作留到下次touch這個塊的時候。(我自己了解的時候注意到,重新整理輸出資料塊的時候,要考慮到作業系統塊和oracle的資料塊是不一樣大小的,是以我覺得這個cleanout操作是在資料緩沖區完成的。恩,是的,調入buffer
catch完成。)
我們首先回憶一下,資料鎖是資料的屬性,它是存儲在資料塊的首部的,當一個大批量的insert 或者 update 結束後,oracle進行commit操作,雖然說這個事務已經送出了,但是還是會有一些資料塊的資料沒有被重新整理輸出到磁盤,(我之前覺得也有可能是已經重新整理輸出後,itl事務槽還沒有被覆寫,但是我看到有人說好像隻要commit完成,就會清除itl事務槽裡面的資訊,保留下commit的SCN号)這時的塊事務槽(也就是ilt事務槽裡面的資料)都還在這個資料塊内,沒有被删除。
當再一次接觸(touch)這些資料的時候(如,select操作,資料塊的下一個讀者首先檢查該塊的事務狀态是否為活動,不活動的話,修改事務的标志(flag)。這樣可以避免不必要的事務讀。),就會去修改這些塊頭,進而産生了不必要的髒資料(因為資料塊被修改成了髒資料,但是資料内容又沒有修改,是以成了假的髒資料,産生不必要的redo
日志)在完成下一個檢查點(check point)的時候會有大量的塊寫入磁盤,(因為檢查點就是階段性的送出,會有很多資料塊重新整理出來)。
下面來看一看送出清除是怎麼工作的:
在與我們的事務相關的送出清單中,oracle會記錄已修改的塊的清單,這些清單的大小時固定的,一個表有20個塊,一個事務可能有很多個這樣的清單,如果我們做強制清除,那麼oracle會設定一個上限,即資料塊緩沖區的10%,超過了這個上限,oracle将不會再給這個事務配置設定清單。commit的時候,oracle就會處理這些清單,oracle回過頭來再到SGA的資料塊緩沖區中通路這些塊(有的塊可能已經重新整理輸出到了磁盤,這些隻能下次通路的時候再做塊清除咯),如果塊可用(沒有别的事務正在給他加鎖修改這個塊)那就完成清理(當做fast
commit cleanout時,oracle不會清理 Row locks lb标志位,ITL lck标志位。),删除itl事務槽裡面的事務資訊。
delayed block cleanout中讀(如select)操作是如何工作的:
當一個程序讀到一個塊的時候, 必須確定一點:塊上的 itl SCN号必須小于這個程序的讀SCN号(如果大于,那就說明又有另一個事務對塊做了操作,必須到undo段裡去讀原來的舊資料鏡像),如果不進行塊清除,itl 事務槽裡也就沒有送出SCN(COMMIT SCN ),這時,這個讀程序先去復原段中嘗試找真實的 commit scn,也就自然的找到上次送出的scn ,再判斷一下上次送出的scn和這次查詢的scn誰大誰小,如果這次查詢scn小于上次送出scn,則根據復原條目進行復原,找到那時的資料進行讀取。這時,也就做了delayed
block cleanout,把沒有commit scn的塊标上scn,下次再來查詢的時候就不用跑到undo段裡去了,直接根據 塊首itl槽裡的commit scn 判斷是否需要進行復原。還有意外,那就是如果復原段被覆寫了咋辦?隻要 讀scn 能在復原段裡找到了比他小的最小scn,那就将這個commit scn 标記為 復原段中所能找到的最小scn。(就是說延遲塊清除的事物肯定是早已經送出了的,沒有從復原段找到他對應的scn,說明已經被覆寫,從復原段找個min
scn就可以,這個min scn肯定是比延遲塊清除事物的scn大。)
延遲清除的塊在被select 時,如果讀的select 的scn 比這個復原段裡面最小的scn 還要小的話(復原段已回繞),那麼在復原段裡面找不到數
據了,oracle 就沒有辦法判斷select 的SCN 與被要清除的資料塊的大小關系,于是ora-01555就出現了,這個時候oracle 就不知道資料塊裡面
的資料是不是是查詢時刻需要的資料.
如果查詢 scn 小于復原段中所能找到的最小 scn ,并且 所需要的復原段資訊又被覆寫了,則發生1555 錯誤。
對于為什麼要用最小的scn更新itl,對于查詢安全要怎麼了解 :
cleanout 的事務配置設定一個從復原段中找到的最小事務scn。這雖然不準确,但是是安全的,對于資料通路也不構成影響。是以叫
upper bound ,猜測的一個scn的上限。
另一種情況是delayed block cleanout,當transaction還未commit或rollback時modified block已經被寫回磁盤,當發生commit時oracle并不會把block重新讀入做cleanout,而是把cleanout留到下一次對此塊的dml或select。當delayed cleanout時候如果undo
segment header的transaction table slot還沒有被覆寫,那麼可以找回該事務遞交的exact scn,如果slot已經被覆寫,那麼将會使用undo segment header中的control scn來做為upper bound scn。
針對讀一緻性考慮:
每個資料頭部都會記錄一個送出SCN,當資料更改送出後,送出scn同時被修改,這個scn在查詢時可以用來進行一緻性判斷.
假如:查詢開始時間為T1,則在查詢擷取的資料塊中,如果資料塊的送出scn小于T1,則oracle接受該資料,如果送出的scn大于t1或者資料被鎖定修改尚未記錄commit scn,則oracle需要通過復原段構造前鏡像來傳回結果.
關于ORA-01555的了解:
如果當一個查詢觸發延遲塊清除的時候,ORACLE 需要去查詢復原段獲得該事務送出的SCN,如果事務前鏡像資訊已經被覆寫,并且查詢的SCN小于復原段記錄中記錄的最小送出SCN資訊,那麼oracle将無法判斷查詢的scn和事物送出scn的大小.
如果當一個查詢觸發延遲塊清除的時候,ORACLE 需要去查詢復原段獲得該事務送出的SCN,如果事務前鏡像資訊已經被覆寫,并且查詢的SCN大于復原段記錄中記錄的最小送出SCN資訊,則将commit 标記為 復原段中所能找到的最小 scn(對于查詢安全).
下面我們對塊清除做一個總結:
我們已經讨論過塊清除機制,不過這裡可以做一個總結:在塊清除過程中,如果一個塊已被修改,下一個會話通路這個塊時,可能必須檢視最後一個修改這個塊的事務是否還是活動的。一旦确定該事務不再活動,就會完成塊清除,這樣另一個會話通路這個塊時就不必再曆經同樣的過程。要完成塊清除,Oracle 會從塊首部确定前一個事務所用的undo 段,然後确定從undo 首部能不能看出這個塊是否已經送出。可以用以下兩種方式完成這種确認:
一種方式是Oracle 可以确定這個事務很久以前就已經送出,它在undo 段事務表中的事務槽已經被覆寫。
另一種情況是COMMIT SCN 還在undo 段的事務表中,這說明事務隻是稍早前剛送出,其事務槽尚未被覆寫。
再者就是undo段内事務表中有這個塊對應的事務送出scn,但是沒有對應的塊首部commit scn,這說明這個事務需要做塊清除(我自己的思想)