教你如何成為Oracle 10g OCP - 第七章 undo表空間管理

tolywang發表於2010-10-18


概念: 對於DML來說,只要修改了資料塊,Oracle就會將修改前的資料保留下來。
分類: 從Oracle9i開始,undo管理分為兩類,Auto Undo Manangement(AUM)和MUM .
Oracle9i之前只能使用MUM, MUM中undo segment又叫做rollback segment, 從9i開始
Oracle就建議用AUM .

 

7.1  DML語句與UNDO

例子:  update t set col1='A' where col1='B' ;
(1). 在shared pool 中進行解析生成執行計劃
(2). 假設col1='B'的記錄存放在10# file, 54號block中;
(3). Server process在buffer cache中找一個可用的undo block,若沒有,到undo
表空間中找一個可用的undo block,調入buffer cache中,假設獲得的undo塊號為24,
是11號undo datafile中;
(4). 將改變前的col1的值B存放在24號undo block中;
(5). 這時buffer cache中的undo block發生變化,於是產生重做記錄(在log buffer中)
重做記錄行號    事務ID    file#    blk#   row   column   value
   120            T1        11      24     10     col1     B
(6). 在buffer cache中查詢54號資料塊,如果沒有,從10號資料檔案中調入buffer
cache ;
(7). 將update後的值'A'放入54號block (記憶體中叫做buffer)中;
(8). 由於54號資料塊在buffer cache中發生變化,於是在log buffer中產生一筆重做
記錄 。
重做記錄行號    事務ID    file#    blk#   row   column   value
   121            T1        10      54    10     col1      A 
(8). 控制權返回給使用者,表現為游標返回。
(9). 當使用者發出commit, 觸發LGWR, 將120,121重做記錄寫入redo log file中,並將
24號和54號資料塊頭部記錄的事務狀態設定為已提交;
(10). 這時在buffer cache中更新後的54號data block和24號undo block並不一定被
DBWn寫入datafile中,只有當dirty block達到一定程度或發生完全檢查點才會被寫入,
因為增量檢查點觸發DBWn啟動的條件的優先順序較低。  事務只要被提交或回滾,該事務
所用的undo塊就可以被覆蓋。

 


7.2 Undo的作用:  一致性讀和回滾事務

(1). 一致性讀(Consistent Read) -- 是相對與髒讀(dirty read)而言 .

ITL槽  --- 每當一個事務要更新一個block中的資料時,必須先在block的頭部獲取一個
可用的ITL槽,將當前的事務ID,事務所使用的undo block的地址,SCN號及當前事務是否
提交的標記等資訊註冊到ITL槽中。
 
髒讀 ---  8點開始select一個表中10000筆記錄,獲得結果需要5分鐘,在8:01的時候另
一個使用者delete刪除其中的一筆記錄,並提交,如果查詢返回9999,那麼發生髒讀,如果
是10000筆,則發生一致讀,對於Oracle來說,必須提供一致讀。 特別提醒,如果是以上
兩個動作是同一個session上發生的,那麼查出來的記錄會是9999筆 。


Undo是如何實現一致讀 ---- 

使用者A在8點發出查詢select, Server process會將8點那個時間點上的SCN
記錄下來,假設為SCN8.00, 那麼8點整的SCN8.00一定大於等於記錄在所有
資料block頭部ITL槽中的SCN號(如果有多個ITL槽,取最大那個SCN),Server
process掃描表中的block時,會將掃描到的block頭部的ITL槽中的SCN號與
SCN8.00對比,如果block頭部的SCN小於SCN8.00, 說明block在8點後沒有
被更新,若大於,說明該塊在8點後有更新,已不是8點時的資料了,要藉助
undo block, 8:01分,B使用者更新了表T的最後一筆記錄並提交(注意,這裡
不管是否提交,只要使用者B更新了表T,使用者A就會去讀undo資料塊),假設最後
這條被更新的記錄屬於N號block, 那麼這時N號block頭部的ITL槽的SCN號被
改為SCN8.01 ,當Server process查詢掃描到這個被更新的N號資料塊時,發現
該塊ITL槽中SCN8.01大於使用者A發出查詢時候的SCN8.00, 說明該塊被更新了,
於是server process到被更新的N號資料塊頭部找到SCN8.01所在的ITL槽,
這個ITL槽中記錄了對應的UNDO塊的地址,於是根據地址找到undo塊,將undo
塊中存放的的前映象取出,再結合N號塊的資料行,從而構造出8:01分被更新
之前的那個時間點的資料塊內容。 這樣的block叫做CR塊(Consistent Read),
比如delete, 其undo資訊是insert, 即構建CR塊中就插入了被刪除的那條記錄。
隨後,server process掃描該CR塊,從而得到正確的10000筆記錄。


----------------------- 


假設在同一個block(N號塊),在9點使用者A發出查詢,需要15分鐘查詢完成,9點
10分的時候B使用者刪除了最後一條記錄並提交,9點11分,C使用者在同一個block
中插入了兩條記錄,假設表的initrans 及ITL槽只有1個),Oracle如何實現一致
讀呢 ?  提交回滾導致ITL槽記錄的已經是SCN911, 而不是SCN910, 即ITL槽
被覆蓋了,Oracle如何找回最初的資料呢 ?

Oracle在記錄undo資料的時候,不僅記錄了改變前的資料,還記錄了改變前
的資料所在的資料塊頭部的ITL槽資訊(ITL資訊包括事務ID,使用的undo block
的地址,SCN號及當前事務是否提交等標記資訊) 。

-- 假設N號資料塊中,8:50時的ITL資訊時undo_block0/SCN850
-- 9:10分,B刪除記錄時,Oracle將改變前的資料放到undo塊,假設該undo塊
地址為undo_block1, 同時在該undo塊中記錄刪除前ITL槽資訊,即undo_block0/
SCN850) .
-- 刪除記錄後,N號資料塊的ITL資訊變成undo_block1/SCN910 .
-- 9:11分,使用者在N號塊中插入兩記錄,ORACLE將插入前資料(即刪除兩條記錄)
放在undo塊(undo_block2)中,並將9:11分的ITL槽資訊(即undo_block1/SCN910)
也記錄到undo塊(undo_block2)中。
-- 插入兩條記錄後,該N號塊的ITL槽資訊變成 undo_block2/SCN911 .

OK, 我們開始分析查詢過程。

-- 我們在9點查詢資料到N號資料塊時,查詢到的SCN900小於最新的SCN911,那麼
說明資料塊被更新,於是到資料塊頭部ITL槽中指定的undo_block2地址找該undo塊,
發現該undo塊頭部記錄的ITL為undo_block1/SCN910, SCN900仍然小於SCN910,那麼
Oracle需要繼續根據undo_block1地址找undo塊,發現該undo記錄的ITL資訊為
undo_block0/SCN850, 這時SCN850undo_block2 和 undo_block1資料結合起來,構建CR塊,將當前N號塊資料複製到
CR塊中,先在CR塊中刪除兩記錄(退到9:11分),然後插入被刪除的最後一筆(退回
到9:10分),從而構建出9點時的資料。


--- 經典的ORA-01555錯誤。 在查的過程中,可能會發現當前undo塊中記錄的ITL
槽的SCN號比上一個undo塊裡記錄的SCN還要大,這種情況說明由於事務被提交或
回滾,導致當前的undo塊裡的data被其他事務覆蓋了,無法找到小於等於當前查詢
時間點的SCN號了。 報snapshot too old的錯誤。


--- 回滾事務
Oracle利用記錄在每個block中的ITL槽裡記錄的undo 塊的地址找到該undo塊,然後
從中取出變化前的值,讀入到buffer cache中,從而對變化進行回滾。


--- 例項恢復
SMON 程式完成前滾,然後Open資料庫,SMON檢查undo segment的第一個block記錄
的事務表,將其中未提交也未回滾的異常終止的事務全回滾。

SMON進行例項恢復時,先從controlfile中獲得檢查點位置,SMON到redo log中
找到該檢查點位置,然後從檢查點位置開始向下,應用所有的redo record, 在
buffer cache中恢復到例項crash那個時間點的狀態。(例項恢復是因為:  redo
record已寫入redo log ,但檢查點佇列中的dirty data還沒有完全寫入datafile) .

 


7.3 配置AUM

AUM= Auto Undo Manangement 

要配置AUM ,首選我們需要配置初始化引數undo_management,該引數用來說明undo
的管理方式,取值分別是 auto, manual .

auto   - 表示採用AUM來管理undo .
manual - 表示採用MUM來管理undo, 表示我們要手工建立rollback segment等。

在AUM管理模式下,我們只需要建立undo表空間,並指定初始化引數undo_tablespace,
剩下的工作,包括undo segment的建立,擴充套件,收縮,刪除等,都由資料庫自動完成。

如果我們指定了undo_management為auto, 沒有指定undo_tablespace,那麼系統會查詢
第一個可用的undo表空間,如果沒找到,則使用位於system系統表空間裡的rollback
segment, 這樣會導致系統表空間的壓力。

 

-- 當發生DML操作的時候,伺服器程式會選擇一個undo segment,AUM採用的是事務繫結
undo segment的演算法。
A. 首先嚐試將每個undo segment繫結一個事務,也就是每個undo segment上只被一個
事務所使用。 
B. 如果不能發現完全空閒的(空閒表示沒有與任何事務繫結)undo segment, 則系統會
嘗試將其他離線的undo segment聯機。
C. 如果沒有可用的undo segment進行聯機,則會嘗試建立一個新的undo segment。
D. 如果上面的步驟都沒有成功,比如由於沒有可用空間了,而不能建立新的undo segment,
則事務繫結演算法會去嘗試找最早被使用的那個undo segment。這種情況下,不同的多個
事務才會在一個相同的undo segment裡同時執行。

 

---------------------------------------------------------------------
undo segment的建立、online以及extent的分配原則。

When the undo tablespace is created, a number of undo segments are created.
These are named using the _SYSSMU$ algorithm. Because of the new name,
some commands (alter system dump undo header) require that the undo segment
name be enclosed in double quotes.

The number of undo segments created and brought online is a function of the
SESSIONS parameter. The algorithm is roughly 1 undo segment for each 5 sessions.
All undo segments are placed online when the sessions parameter is set to 46
or greater. The lower limit was not tested, as the minimum value for the
sessions parameter in the test database was 16, which was derived from the
minimum number of processes (10) for the database. These are sized according
to the autoallocate algorithm for locally managed tablespaces. The basic algorithm
is that the first 16 extents are 64k in size. The subsequent allocation method
is the next 63 extents of 1m, the next 120 extents of 8m and all additional
extents at 64m.

The first block of the first undo extent is reserved as the header and not
indicated in the data dictionary views. As with Oracle 8, the second block
of the undo segment is not used initially and may or may not be allocated
at a later time. This is one of those anomalies that has no consistent pattern
and is therefore hard to explain. 

當undo表空間被建立時,很多的undo segments被建立,這些segments以_SYSSMU$
規則來命名。 因為新的名稱,一些命令比如alert system dump undo header 需要在
undo segment的名稱上加註雙引號。

Undo segment建立和線上數量是由引數SESSIONS決定的,粗略演算法為每5個session對應
一個undo segment, 當sessions引數設定為46或更大時所有的undo segments都處於
online狀態。 下限沒有被測試過,因為在測試資料庫中sessions引數最小值是16,
這個值來自於資料庫中引數processes的最小值10,這些大小是參考本地管理表空間
(LMT)自動分配演算法而來。 基本演算法是: 前16個extents大小為64K, 隨後63個extents
是每個1M, 然後120個extents是每個8M, 再後面的extents大小都是64M不變。

第一個undo extent的第一個block保留作為頭部,沒有在資料字典中標示出來,與Oracle
8 一樣,undo segment的第二個block最初沒有被使用,後面一段時間也許被分配,也許
不會,這是異常現象之一,沒有統一的模式,因此很難解釋。

---------------------------------------------------------------------

 

既然存在undo segment的擴張(當併發事務的數量超過線上undo segment的數量時undo
segment被smon自動建立),就存在undo segment的收縮。收縮由SMON完成,在下面的
情況下會收縮undo segments:
A. 每隔12個小時會收縮一次,刪除那些idle狀態的extents;
B. 當前臺程式進行DML而需要undo時,發現空間不夠用,則會喚醒SMON進行一次收縮。
也就是說,將其他undo segment裡暫時沒被使用的extent拿過來用。

Oracle為undo的管理提供了另一個引數:undo_retention。該引數以秒為單位,表示當
事務提交或回滾以後,該事務所使用的undo塊裡的資料需要保留多長時間;當保留的時
間超過undo_retention所指定的時間以後,該undo塊才能夠被其他事務覆蓋。

 

當我們使用AUM,並設定了undo_retention以後,undo塊就存在四種狀態。
a. Active:表示正在使用該undo的事務還沒有提交或回滾。
b. Inactive:表示該undo上沒有活動的事務,該狀態的undo可以被其他事務覆蓋。
c. Expired:表示該undo持續inactive的時間超過undo_retention所指定的時間。
d. Freed:表示該undo塊內容是空的,從來沒有被使用過。

 

當活動的事務使用undo segment時,在AUM下,事務可以在不同的undo segment
之間動態交換undo空間(也就是extents),當一個執行的事務需要更多的undo空間
時,首先會重用當前undo segment裡的可用空間,如果不足,則按照下面步驟獲
取所需要的extent :
a. 獲取undo表空間中可用的,空的extents;
b. 獲取其他undo segment裡的expired狀態的extents;
c. 如果undo資料檔案啟用了自動擴充套件,則檔案自動擴充套件;
d. 如果undo檔案都沒有啟用自動擴充套件,則獲取其他undo segment中inactive的;
e. 如果以上步驟均無法獲得可用空間時,報空間不足的錯誤訊息.

從這裡可以看出,在AUM裡,分配undo塊的演算法不僅有效,而且會盡可能地將INACTIVE
狀態的extents保留足夠長的時間。在Oracle10g裡,如果undo表空間有足夠的可用空間
,則Oracle會將undo資訊保留的時間與當前執行時間最長的那個查詢所需要的時間相同。

 

undo_retention 預設值為900秒,Oracle不會自動調整undo_retention,使用
我們設定的該值作為undo保留的時間。

如果我們沒有為該引數指定值,或指定了0,則Oracle會自動調整undo retention,
並以900秒作為最低值。Oracle 10g 會每隔30秒鐘就收集統計資訊來自動調整undo
retention,收集的資訊包括執行時間最長的查詢、產生undo的速度等。

如果設定undo_retention為0,則例項會獲取執行時間最長的那個查詢所需要的時間,
比如為N秒,然後將undo資訊保留N秒。當undo表空間的尺寸太小,而不能保留這個最長
的時間時,則會盡可能地利用現有的可用空間來讓undo保留的時間儘可能長,並不會立
刻擴充套件undo資料檔案。除非要覆蓋的undo資訊是在距今900秒以內發生的,才會去擴充套件數
據檔案。

 


7.4  管理undo表空間

與普通表空間管理差不多。

資料庫中可以同時存在多個undo表空間,但是在一個時間點上,資料庫只能使用
一個undo表空間。如果我們將undo_tablespace引數設定為另外一個undo表空間的
名字,則這叫做undo表空間的切換。

 

如果有事務還在undotbs1上執行,這時我們切換undo_tablespace時,舊的undo
表空間變成pending offline狀態,不能被使用,也不能被刪除。最終,當舊的
undo表空間上的所有的事務都提交以後,舊的undo表空間從pending offline狀
態變成offline狀態,這時我們才可以刪除該舊的undo表空間。

-- 實驗:

a. 可以先寫個程式段,指定使用undotbs1 ;
b. 程式中的update動作不提交 ;
c. 再切換undo表空間到undotbs2 ;
d. 檢視舊的表空間轉檯;
e. 提交update動作後再次檢視狀態;


一個undo 表空間只有在當前沒有被活動的事務使用的時候才被刪除。如果drop
tablespace後面跟的是某個undo表空間的名字,就相當於發出drop tablespace
... including ontents命令。

我們在切換undo_tablespace以後,應該在等待的時間超過undo_retention的長
度以後再刪除舊的undo表空間。因為drop tablespace命令能夠刪除那些含有
inactive狀態的undo塊(這些undo塊還沒有expired)的undo表空間, 這可能
導致ora-01555錯誤。

 


retention guarantee

-- 為了徹底防止保留時間小於undo_retention的undo 資料塊被覆蓋,Oracle引入
了retention guarantee屬性。

retention guarantee屬性可以在建立undo表空間時指定,也可以在建立完畢
以後設定:

SQL> create undo tablespace undonew1 datafile
'/u01/app/oracle/oradata/ora10g/undonew01.dbf'
size 10M autoextend on maxsize 100M retention guarantee;

SQL> alter tablespace undonew retention guarantee;

若要取消retention guarantee屬性,則使用下列命令:
SQL> alter tablespace undonew retention noguarantee;

 

 

--  計算undo空間的大小

在我們計算undo表空間大小時,可以藉助檢視v$undostat。Oracle每隔10分鐘
更新該檢視,將這10分鐘裡產生的undo塊的個數記錄在該檢視裡。Oracle在
v$undostat裡保留最近7天的資料,也就是1008行記錄。

因此,透過該檢視,我們可以計算undo表空間應該設定多大,Oracle提供瞭如下公式:
UndoSpace = Undo Retention * Undo Per Second + overhead(24 undo blocks)

其中,undo retentio就是系統中執行時間最長的那個查詢所花費的時間,我們把該
時間設定到初始化引數undo_retention上去。而Undo Per Second則可以透過查詢
v$undostat來計算:

Select blks/((end-begin)*3600) as "Undo Per Second" from
(Select min(begin_time) begin,max(end_time) end,sum(undoblks)
blks from v$undostat);

當然,在判斷undo表空間應該設定多大時,藉助Database Control所提供的Undo
Advisory會更加簡單。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/35489/viewspace-676213/,如需轉載,請註明出處,否則將追究法律責任。

相關文章