天天看點

管理還原資料

UNDO 表空間管理

1、對于DML語句來說,隻要修改了資料塊,Oracle資料庫就會将修改前的資料塊保留下來,儲存在undo segment裡面,而undo segment則儲存在undo表空間中

2、undo的管理

自動undo管理(Oracle9i開始)AUM

手工undo管理MUM

9i以後,就建議使用AUM,是以就不再讨論MUM

一條DML語句的執行流程update t set coll=‘A’ where coll=‘B’

1、在shared pool裡面進行解析,進而生成執行計劃

2、根據執行計劃,得出coll=‘B’的記錄存放在10号資料檔案的54号資料塊裡面

3、伺服器程序首先在buffer cache尋找一個可用的undo資料塊(如果一個事物已經送出,那麼這個事務曾經使用過的undo資料塊就可以被使用),如果沒有發現,則到undo表空間裡找到一個可用的undo資料塊,并調入到buffer cache。假設獲得的undo資料塊号為24号,位于11号undo資料檔案裡

4、将改變前的值,也就是B放入24号undo資料塊(buffer cache中)

5、由于undo資料塊發生了變化(隻要是資料塊發生變化,那麼就産生重做記錄),于是産生重做記錄,假設重做記錄号是120

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095988U3yk.png"></a>

6、在buffer cache裡面找到54号資料塊,如果沒有,則從10号資料檔案調入

7、将改變後的值,也就是A放入54号資料塊

8、由于資料塊發生了變化,于是産生重做記錄,假設重做記錄号是121

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095988ImLT.png"></a>

9、控制權傳回給使用者,如果使用SQLPLUS,那麼表現為光标傳回

10、使用者發出commit指令,觸發LGWR,将120、121這兩個重做記錄寫入聯機重做日志檔案中,将54号、24号兩個資料塊頭部所記錄的事務狀态标記設定為已送出,控制權傳回給使用者,如果使用SQLPLUS,那麼表現為光标傳回

11、這個時侯,54号和24号資料塊并不一定被DBWr寫入資料檔案,隻有在髒資料塊的數量達到一定程度的時候才會被寫入

事務送出以後,該事務所使用的undo資料塊就可以被覆寫,上面的例子中,第10步使用者送出以後,24号undo資料塊就可以被覆寫

Undo的作用

1、提供讀一執性

2、復原事務

3、執行個體恢複

讀一緻性

一個場景描述

讀一緻性是相對髒讀而言的,表T中有10000條記錄,擷取所有的記錄需要15分鐘的時間,目前時間為9點整,使用者發出一條select * from T指令,該語句在9:15完成。當使用者執行該語句到9:10分的時候,另外一個使用者發出了一條删除指令,将最後一條記錄删除,并且進行了送出。

到9點15分的時候,使用者傳回了多少條記錄。

如果是9999條,那麼就是髒讀、如果是10000條,那麼就是讀一緻性。

Oracle不會出現髒讀,提供讀一緻性,而且沒有阻塞DML操作

Oracle如何實作讀一緻性呢?

1、使用者在9點發出select語句的時候,伺服器程序會記錄9點那個時刻的SCN号(SCN号是以時間(timestamp)作為參數的一個函數傳回值,調用函數(預設以timestamp為參數)随時可以傳回這個時刻的SCN号,可以使用函數在SCN和timestamp之間進行轉換),假設該SCN号是SCN9:00,那麼SCN9:00一定大于等于記錄在所有資料塊頭部的ITL槽中的SCN号(如果有多個ITL槽,SCN最大的那個)

2、伺服器程序掃描T表的時候,會把掃描的資料塊頭部的ITL槽中的SCN号與SCN9:00進行比較,哪個更大。如果資料塊頭部的SCN小于SCN9:00,那麼說明這個資料塊在9:00以後沒有更改過,可以直接讀取,如果資料塊頭部的SCN号大于SCN9:00,則說明該資料塊在9:00以後更改過,已經不是9:00那個時刻的資料了于是要借助undo塊

3、9點10分,使用者更改了T表的最後一條記錄并送出(無論是否送出,隻要是更改了T表,使用者就會去讀undo資料塊),假設被更改的是N号資料塊,那麼N号資料塊頭部的ITL槽中記錄的SCN被修改為SCN9:10,當伺服器程序掃描到這個資料塊的時候,發現ITL槽中的SCN9:10大于SCN9:00,說明該資料塊在9:00以後被更新了,于是伺服器程序到N号塊的頭部,找到SCN9:10所在ITL槽,由于ITL槽記錄了對應的undo塊的位址,于是伺服器程序找到undo資料塊,結合undo資料塊給使用者提供讀一緻性。

進一步複雜化問題

1、9點10分,更新了資料并且進行了送出,9點11分又對該資料塊進行了更新并且送出(假設資料塊隻有一個ITL槽)

2、那麼該ITL槽記錄的就是SCN9:11

3、這種情況如何處理,秘密在于undo資料塊中,除了記錄改變前的資料以外,因為資料塊的ITL槽也發生了變化,是以也進行了記錄,而ITL槽中記錄了undo塊的位址。9:00的時候資料塊的ITL槽中記錄了資料塊的SCN是8:50和對應的undo塊,9:10分的時候資料庫的ITL槽中記錄了資料塊的SCN是9:10和對應的undo(undo1),9:11分的時候資料庫的ITL槽中記錄了資料塊的SCN是9:11和對應的undo(undo2),Undo2中記錄了9:10的資料,以及9:10資料的undo位址undo1,undo1中記錄了9點以前的資料以及9點以前的undo資料

當使用者進行查詢的時候,伺服器程序掃描到N号資料塊,發現SCN9:11,大于SCN9:00,從ITL槽中找到undo塊的位址(undo2),undo2中記錄了改變前的資料和改變前的資料庫的ITL槽,發現undo2對應的SCN是9:10還是大于9:00,根據undo裡面記錄的ITL槽的改變前資訊,繼續向前找,找到undo1,發現SCN是8:50,小于9:00,使用這個undo的資料

如果在向前尋找的時候,沒有找到SCN小于9:00的資料(因為時間比較長,而且事務已經送出,是以復原段可能被覆寫),資料庫就會出現一個經典的錯誤ORA-01555(snapshoot too old),但是不會出現髒讀的情況。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095988LoMd.png"></a>

最核心的就是:資料塊的資料發生改變,ITL槽也發生改變。這兩條資訊都會存儲到undo中。是以如果一個undo足夠的大,那麼一個資料塊的所有的undo資料塊是可以串聯起來的。可以從最近一直找到非常遠的過去。從資料塊開始往前找,一直找到很久以前的SCN。這個資料塊所有的變化都能夠找到。

ITL槽中記錄着這個資料塊的undo資料塊的位址。

一個資料塊中存儲很多條資料,update、insert、delete等DML操作,都會影響資料塊的SCN号。資料塊的SCN号反映了資料塊的變化過程。

復原事務:錯誤或者rollback指令都會産生復原

根據ITL槽中記錄的undo資料塊的位址,找到undo資料塊,恢複資料。

執行個體恢複

復原段的頭部記錄了事務表,每一個事務是否送出等資訊都存儲在裡面。

根據事務表的資訊進行執行個體恢複。

配置AUM

Oracle9i開始,我們不再使用手工的管理方式,是以“MANUAL”不再使用,使用“AUTO”

使用AUM需要配置兩個參數

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095989bp8r.png"></a>

指定這兩個參數以後,剩餘的工作讓Oracle來處理,例如undo segment的建立、擴充、收縮、删除等。

如果指定了undo_management,但是在指定undo_tablespace的時候,指定了一個錯誤的復原表空間,執行個體啟動的時候,會報錯。

如果沒有指定復原段表空間,系統查找第一個可用的復原段表空間,如果沒有找到,那麼就使用system表空間中的復原段,這不是我們希望看到的,因為對性能影響很大。

是以兩個參數都要很好的規劃

事務、undo segment

發生DML操作的時候,伺服器程序會選擇一個undo segment,具體算法如下:

1、首先嘗試将每一個undo segment綁定一個事務,也就是每個undo segment上隻有一個事務使用

2、如果不能發現完全空閑的undo segment,所有的undo segment都與事務綁定

3、系統嘗試将脫機的undo segment聯機

4、如果沒有可用的undo segment進行聯機,則會嘗試建立一個新的undo segment

5、如果上面的步驟都沒有成功(例如沒有可用空間了,不能建立undo segment),算法會嘗試尋找最早使用的undo segment,這種情況下,不同的多個事務會在同一個相同的undo segment裡同時進行

6、每隔12個小時會收縮一次,删除那些idle狀态的extent

7、DML操作需要undo時,發現空間不夠,則會喚醒SMON進行一次收縮,将undo segment裡面暫時沒有使用的extent拿過來使用

Oracle 在提供一緻性讀的過程中,具體的步驟如下

1、确認讀時刻的SCN

2、搜尋所有的資料塊的SCN要求小于讀時刻的SCN

3、如果搜尋的SCN小于讀時刻的SCN,直接讀取

4、如果搜尋的SCN大于讀時刻的SCN,根據資料塊裡面的ITL槽裡面記錄的undo資訊,找到改變前的資料、如果SCN還是大,順着ITL槽資訊串聯起來的undo塊繼續向前找

5、如果沒有找到小于讀時刻的SCN的資料塊,那麼就報錯ORA-01555

事務送出以後,undo復原段就可以被覆寫,而且我們在尋找undo資料塊的時候,這個被尋找的undo資料塊很可能已經被送出,是以出現ORA-01555錯誤不可避免。Oracle是如何來解決這個問題的呢?

Oracle定義了一個參數undo_retention

這個參數以秒為機關,表示當事務送出或者復原以後,該事務所使用的undo 塊裡的資料需要保留多長時間。

當保留的時間超過undo_retention所指定的時間以後,該undo塊才能夠被其他事務覆寫。

當我們使用AUM的時候,并且設定了undo_retention以後,undo塊的狀态就存在4種

Active:表示正在使用該資料塊的事務還沒有送出或者復原

Inactive:該資料塊上沒有活動的事務,該狀态的undo可以被其他事務覆寫

Expired:該資料塊持續inactive的時間超過undo_retention所指定的時間

Freed:該資料塊是空的,從來沒有被使用過

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095989ae0Q.png"></a>

在AUM模式中,事務可以在不同的undo segment之間動态交換undo空間,也就是在不同的undo segment裡交換extents。

我們來看一下,一個事務需要更多的undo空間的時候,是如何進行處理的?

1、擷取undo表空間裡可用的、空的extents(segment的最小配置設定單元是extent)

2、擷取其他undo segment裡的expired狀态的extents

3、如果undo表空間裡的資料檔案啟用了自動擴充,則資料檔案進行自動擴充

4、如果undo表空間裡的資料檔案沒有啟用自動擴充,則擷取undo segment裡的inactive狀态的extents

5、如果還是沒有獲得可用空間,報空間不足的錯誤

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095990m8no.png"></a>

1、undo表空間中一共存在5個undo segment

2、每個undo segment包括7個extents

3、當使用US5的事務需要額外的空間的時候,首先使用兩個F狀态的extent,如果還不夠用,繼續使用US4裡面三個F狀态的extents,如果還不夠用,使用US3裡面X狀态的extents,如果還不夠用,繼續使用US1裡面I狀态的extent,如果還不夠用,報空間不足的錯誤。

假設上面的資料檔案沒有配置自動擴充

1、AUM裡面配置設定extent的方式是高效率的,而且盡量避免使用I狀态的extent。

2、在Oracle10g裡面,如果undo表空間足夠,那麼Oracle會将undo資訊保留的時間與目前運作時間最長的查詢所需要的時間相同(一個很好的優勢,最大限度的避免了ORA-01555)

3、預設情況下,Oracle每隔30秒就收集統計資訊來自動調整undo retention,收集的資訊包括運作時間最長的查詢與産生undo的速度

我們通過設定undo_retention為0,那麼就使用上面的自動調整功能,而且以900秒為最低限

如果我們設定了undo_retention,那麼就使用這個參數作為undo_retention的值,不再支援動态的調整undo_retention

4、如果undo_retention設定為0,則執行個體會擷取運作時間最長的那個查詢所需要的時間,例如N秒,然後将undo資訊保留N秒,當undo表空間尺寸太小時,而不能保留這個最長時間,則盡可能的利用現有空間來讓undo保留的時間盡可能的長,并不會立刻擴充undo資料檔案,除非要覆寫的undo資訊是在900秒以内發生的,才會去擴充資料檔案。

管理undo表空間

1、一些正常性的操作,例如添加資料檔案、重命名資料檔案、将資料檔案聯機或者脫機,和普通的表空間操作沒什麼兩樣。

可以通過EM來進行操作

2、一個資料庫可以有多個undo表空間,但是在一個時刻,隻能有一個undo表空間起作用,通過參數undo_tablespace設定來指定一個undo表空間

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095990z345.png"></a>

上面做了一個undo 表空間的切換

1、舊的表空間上有事務正在執行,則該舊的表空間變成pending offline。

2、使用者事務正常運作,切換操作結束,不會等待舊的undo表空間的事務結束

3、切換以後,所有新的事務所産成的undo資料不會存放在舊的undo表空間,而是會使用新的undo表空間

4、pending offline狀态的undo表空間不能被删除

5、舊的undo表空間上的所有的事務都送出以後,舊的undo表空間從pending offline狀态變成offline狀态,表空間可以删除

6、drop tablespace undotbs1相當于drop tablespace undotbs1 including contents

7、如果undo表空間包含inactive狀态的undo資料塊,不影響被删除,但是可能産生ORA-01555錯誤,是以最好等待超過undo_retention以後,再删除表空間

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095990IAVj.png"></a>

建立第三個undo表空間

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095991JrnM.png"></a>

建立表test并插入一條資料

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095991Ei7S.png"></a>

顯示目前的活動事務,以及對undo的使用。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095992oEM5.png"></a>

Undo表空間直接被删除,為什麼呢?

因為我們認為在undo表空間上有活動事務。

因為在同一個會話中,如果有DDL語句,那麼前面的事務會被送出。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095992bcGQ.png"></a>

檢查復原段裡的資訊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095993oFMJ.png"></a>

插入一條資料,繼續檢查復原段裡的資訊

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095993Rpg8.png"></a>

另起一個會話,切換了undo表空間。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095993rUo2.png"></a>

會話還在,沒有被送出。

表空間不能被删除。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095994QJDc.png"></a>

回到原來的會話中,将事務送出。

已經沒有會話,為什麼還不能被删除。

這就涉及了另外一個話題

Undo_retention參數不能保證undo資訊保留足夠的時間,oracle隻是盡量的保證undo資料塊不被覆寫掉,當空間不夠的時候,Oracle還是會将保留時間小于undo_retention的undo資料覆寫掉。

從Oracle 10g開始,我們可以在建立undo表空間的時候,設定retention guarantee屬性,進而讓不會出現上面的情況。

也就是說

當undo資料檔案不能擴充,并且undo資訊不夠用時,直接報錯,而不是覆寫那些inactive而又沒有expired的undo塊。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095994DzfD.png"></a>

經過15分鐘以後,也就是undo_retention以後,表空間可以被删除。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095995Q80j.png"></a>

表空間的這個參數是可以修改的。

設定Undo表空間的大小

1、借助視圖,看一下每隔十分鐘産生的undo塊的數量,oracle會保留最近7天的資料

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095995trPy.png"></a>

如果資料庫啟動足夠長的時間,那麼會保留7天的資料,也就是1008行資料。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095996iPiv.png"></a>

有公式可以計算如何設定undo的大小。但是我們最好還是借鑒Oracle提供的advisor。

<a href="http://bearlovecat.blog.51cto.com/attachment/201205/4/1293914_1336095996jnPP.png"></a>

根據系統的負載,不同的還原保留時間所需要的undo空間。

本文轉自bear_cat51CTO部落格,原文連結: http://blog.51cto.com/bearlovecat/851838,如需轉載請自行聯系原作者