2021年3月29日 星期一

8.2 Oracle Undo Segment

Oracle Undo Segment 主要的用途是用來存放變更前的資料,當有 DML 行為產生時,DML 所做的變更會記錄到 Redo Log,而這些變更前的資料會暫存在 Undo Segment :

 

存放在 Undo Segment 中的變更前資料,我們將它稱作資料的 “Before Image”,最主要的用途是為了達成資料讀取的一致性,避免讀取到已經變更但尚未 commit 的資料,例如 EMP 這個 table 裡面有一筆 empno=7369、sal=4000 的資料,此時 session1對這筆資料進行變更,將 sal 改為 5000 :

在資料更改的同時,會把 empon=7369、sal=4000 這一筆變更前的資料存入 Undo Segment 中,此時當有 session2 來查詢 empno=7369 這筆資料時,由於之前的變更 (sal=5000) 尚未 commit,所以 session2 查到的會是從 Undo Segment 回傳的 sal=4000 這筆資料。


Undo Segment 除了用來維持資料讀取的一致性外,在做資料庫還原的過程當中也是扮演了重要的角色。當資料庫在進行還原的過程中,需要藉由 Redo Log / Archive log 來將資料還原到最新的狀態,假如資料庫是因為異常中止(crash)而需要進行還原,此時的 Redo Log 裡面就會包含已經 commit 的交易與尚未 commit 的交易,資料庫沒辦法分辨 Redo Log 裡面那些是已 commit 的交易哪些是未 commit,所以會將 Redo Log 裡面的交易通通應用(apply)到資料庫中,然後再藉由檢查 Undo Segment 將那些尚未 commit 的交易進行 rollback,以此達到資料回復到 crash 前的狀態。


Undo Tablespace 這個概念是從Oracle 9i 開始有的,Undo Tablespace 裡面只能存放 Undo Segment ,早期(Oracle 8i)以前稱作 rollback segment 。在 Oracle 8i 以前必須要由 DBA 自行管理所有的 rollback segment,由 ”create rollback segment” 這個命令來建立 rollback segment ,並且設定參數 rollback_segments 來指定所有使用的 rollback segment。到了 Oracle 9i 之後,將 rollback segment 進行自動化管理,DBA 只需要建立一個 Undo Tablespace,隨後的 rollback segment 都交由資料庫自動進行管理。這個設定與三個參數有關,undo_management、undo_retention與undo_tablespace:

  • undo_tablespace: 設定undo tablespace為哪個tablespace。

  • undo_retention: 設定undo tablespace裡面的before image 保留時間,單位為秒。

  • undo_management: 設定 rollback segment的管理方式,AUTO表示自動管理,MANUAL表示手動管理,設定為MANUAL將回到Oracle 8i 之前的管理方式,預設為AUTO。


在 Undo Segment 為自動管理的設定下,我們還是可以透過查詢 dba_rollback_segs 來查看目前所使用的 rollback segments :

只有 SYS 這個使用者所使用的 rollback segment 存放在 SYSTEM 這個 tablespace,其餘使用者所使用的都會是由 Undo Tablespace 自行所產生 “_SYSSMU” 開頭的 rollback segments。


undo_retention 預設為900,表示資料的 before image 只保留在 Undo Tablespace 裡面15分鐘,當 Undo Tablespace 空間不足且有新的 before image 需要放進來時,便會把較舊的 before image 清除掉,讓新的 before image 放進來,若是此時有查詢需要使用 Undo Data 但是 before image 卻被清掉了,這時候就會出現 ”ora-01555:snapshot too old” 的錯誤訊息,必須考慮將 undo_retention 參數加大或是增加 undo tablespace 的空間來避免這個錯誤。透過 dba_undo_extents 可以查詢目前 Undo Tablespace 裡面各個 Undo Segment 的狀態:


  • ACTIVE: 表示這個 Undo Segment正在被使用中。

  • EXPIRED: 表示這個Undo Segment裡面的before image已經超出undo_retention的時間了,標示這區段的before image可以被清除。

  • UNEXPIRED: 表示這區段的 Undo Segment 沒有 session 在使用它,而且也還未超出 undo_retention 的時間,等到它超過 undo_retention 時,狀態就會變為 EXPIRED。


當 Undo Tablespace 的空間不足時且 Undo Tablespace 所使用的 Data File 又沒有設定 autoextend 屬性時,標示為 EXPIRED 或是 UNEXPIRED 的 Segment 都有可能被清除,此時可以為 Undo Tablespace 加上 GUARANTEE 屬性,表示 Undo Tablespace 裡面的 before image 一定會保留到 undo_retention 這麼長的時間不被清掉:

SQL> alter tablespace undotbs1 retention guarantee;

 

透過查詢 dba_tablespaces 裡面的 retention 可以得知目前 Undo Tablespace 是否具有 GUARANTEE 屬性:

 

值得注意的是,當設定為 GUARANTEE 屬性時,如果 Undo Tablespace 空間不足且無法 autoextend ,那麼就會因空間不足而導致作業失敗。


建立 Undo Tablespace 只需要加入 UNDO 關鍵字,其餘操作與一般 Tablespace 無異:

SQL> create undo tablespace undotbs02 datafile '/oradata/undotbs02.dbf' size 1024m;


更改 Undo Tablespace 只需要將參數 undo_tablespace 變更就可以,例如將 UNDOTABS1 更改為 UNDOTABS2 :

SQL> alter system set undo_tablespace='UNDOTBS2';


這個參數可以在線上動態更改,更改完畢後,新的 session 就會使用新的 Undo Tablespace 了,但是舊的 Undo Tablespace 不建議在線上馬上刪除(Drop),原因是在線上有可能有舊有的session仍舊在使用,且尚未 EXPIRED 的 before image 也有可能會被使用,建議將資料庫重啟後再將舊有的Undo Tablespace進行刪除的動作。




沒有留言:

張貼留言