Oracle Flash Back -------閃回到一個合適的時間(轉)

使用一條簡單的SQL語句,把表或者數據庫恢復到過去的某個時間點。



新年的聖誕夜前夕,頂點銀行的DBA約翰正在和他的朋友們一起狂歡,爲新年的到來倒計時。正當午夜的時鐘敲響,大家一起歡呼時,他的手機忽然響了起來。銀行數據中心裏,年終計帳程序正忙於計算利息,但是發生了一些問題,所有的利息都被計算錯了。幸運的是,開發團隊找到了問題所在並且開發了一個應急方案,但是這個方案不能撤消已經造成的損害。運算中心的經理問約翰是否能以某種方式把數據庫恢復到進行利息計算之前的狀態,那時的時間大概是11:00pm。



對於您這位DBA來說,聽上去是不是很熟悉?約翰應該怎麼辦呢?



在Oracle 10g之前,約翰所能做的是建立一個時間點恢復,把數據庫恢復到一個期望的時點上。不幸的是,銀行的每日備份程序在那時還沒有運行,因此他需要使用差不多24小時的歸檔日誌來恢復數據庫。



在Oracle 9i中,有另外一個選擇,可以利用閃回查詢特性把表中的記錄恢復到11:00pm,然後再手工建立一組表。這個方法儘管可能,但是如果表的數量太多的話是不現實的。



Flashabck Table



我們看一下上面的情況,出現問題的利息計算程序可能隻影響了很少的幾個表。比如說,它只是更新了Accounts表中的餘額。如果是這樣,約翰可以利用flashback table特性把表恢復到過去的某個時點。



爲了執行flashback table操作,沒有什麼特別的設置需要做。唯一的要求是打開表的row movement特性,可以在表創建的時候或者利用 ALTER TABLE ACCOUNTS ENABLE ROW MOVEMENT 來完成。FLASHBACK TABLE命令會從回滾段中讀取表過去的鏡像並利用Oracle 9i中引入的閃回查詢技術重新構建表中的記錄。



如果非DBA或者非模式的擁有者需要執行FLASHBACK TABLE操作,她需要有該表的SELECT, DELETE, INSERT, ALTER和FLASHBACK權限,或者具有等價的ANY TABLE系統權限。


對於約翰來說,ACCOUNTS表如下:

ACCOUNT_NO NUMBER(12),
BALANCE NUMBER(15,2)
STATUS CHAR(1)
STATUS列的值通常情況下是"A"(active),但是當利息計算程序啓動時,所有的賬戶都被凍結,STATUS字段被更新成"F"(frozen)。當該賬戶的利息計算完成時,STATUS標誌被更新成"I"(interest applied)。



下面是約翰爲了使用FLASHBACK TABLE特性所遵循的步驟:

他詢問需要把數據庫恢復到得大概時點,答案是大約11:00pm。
他定義了需要恢復到的邏輯狀態。下面是現在查詢該表時得到的結果。
select status, count(*)
from ACCOUNTS
group by status;

STATUS COUNT(*)
------ --------
I 27088
F 19999
結果顯示迄今爲止已經有27088個賬戶被處理過(status=I)。他需要恢復到的邏輯狀態是所有的的賬戶的狀態爲"F",在這之前的狀態是"A"。他必須把所有的賬戶狀態恢復到"F",大概在11:00p.m。
他查看了一個狀態爲"I"的現有賬戶,並且把它作爲將來測試時的驗證基準。
select account_no, balance
from ACCOUNTS
where status = 'I'
and rownum < 2;
ACCOUNT_NO BALANCE
----------- --------
21633 3913.49
他執行了下面的命令把ACCOUNTS表恢復到11:00p.m時的狀態:
flashback table ACCOUNTS to timestamp
to_timestamp ('12/31/2003 23:00:00','mm/dd/yyyy hh24:mi:ss');
哇!整個表被恢復到了指定的時間戳,約翰可以把它恢復到回滾段允許的任意遠的時間點。除了使用時間戳,還可以使用系統修改號(SCN),如下:
flashback table ACCOUNTS
to SCN 9988653338;
表被恢復到11:00p.m,但是它是不是我們期望的點呢?約翰再次檢查了賬戶的狀態:
view plain
select status, count(*)
from ACCOUNTS
group by status;

STATUS COUNT(*)
------ --------
I 88
F 46999
仍然有88條記錄的狀態爲"I",所以11:00p.m還不夠早;約翰還需要把表恢復到更早的時間。他把表閃回到10:30p.m然後再次查看賬號狀態:
flashback table ACCOUNTS to timestamp
to_timestamp ('12/31/2003 22:30:00','mm/dd/yyyy hh24:mi:ss');

select status, count(*)
from ACCOUNTS
group by status;

STATUS COUNT(*)
------ --------
A 47087

約翰閃回的太遠了,所有的賬號狀態都是"A",在"F"之前的狀態。因此,應該選擇更近一點的時間10:45p.m。
flashback table ACCOUNTS to timestamp
to_timestamp ('12/31/2003 22:45:00','mm/dd/yyyy hh24:mi:ss');

select status, count(*)
from ACCOUNTS
group by status;

STATUS COUNT(*)
------ --------
F 47087
現在的結果正是我們想要的,他查詢了之前作爲基準賬戶的信息:
select balance
from ACCOUNTS
where account_no = 21633;

BALANCE
-------
3836.75
這個賬戶之前的餘額是$3,913.49,現在時10:45p.m的狀態。操作完成了,flashback命令可以向前或向後閃回到某個精確地時間點。
因爲表從來沒有被drop掉,所有依賴它的對象-----例如索引、約束、觸發器等都是完好可用的。所有引用了該表的獨立對象,例如存儲過程也是有效地。

如果除了ACCOUNTS表外,約翰還想閃回TXN表,那麼他可以利用逗號來分隔這些表,從而一次閃回多個表:

flashback table BANK.ACCOUNTS, bank.txn to scn 1234567;

整個表的閃回操作通過一條強大的SQL語句來完成。



我們看一下另外一種情況,假如勞拉不小心drop了一個關鍵的查找表GL_MASTER。發現錯誤後,她問約翰可不可以恢復這張表。在Oracle10g中,drop一張表時只是重命名了這個表並且把它放入邏輯容器回收站中。



爲了恢復這個表,約翰執行了下面的命令:

flashback table gl_master to before drop;
不需要任何恢復工作,這張表立刻就重現出現了。注意,不像之前的閃回操作,這個操作不需要從回滾段中重建數據,只是把表從回收站中移了回來。



Flashback Database

當邏輯錯誤不止發生在幾個表上時,直接使用Flashback Database命令可以把數據庫更快的恢復到之前的時間點。Flashback Database命令不是使用回滾段,而是使用磁盤上的一個被稱爲閃回恢復區來恢復數據庫。利用Flashback Database命令,不用使用數據庫備份就可以恢復數據庫。



爲了閃回整個數據庫,約翰需要做下面的準備工作,從而使數據庫具有可被閃回的能力:

通過設置下面的參數配置一個2G大小的閃回恢復區:
db_recovery_file_dest = /usr/users/oracle/10.1/recovery_area
db_recovery_file_dest_size = 2G
使用下面的參數配置一個以分鐘爲單位的最大閃回時間:
db_flashback_retention_target = 1440
這個值代表了最大的可閃回的時間,最大的可能時間由閃回恢復區的可用空間決定。以上的三個參數都可以通過ALTER SYSTEM命令設置。
使數據庫可閃回,數據庫必須工作在archivelog模式。在MOUNT階段,OPEN之前,約翰執行了下面的命令:
alter database flashback on;
當允許FLASHBACK DATABASE的時候,它將定期的把對數據塊的修改寫到一個特定類型的日誌中,這個日誌叫閃回日誌。這些日誌不是由傳統的日誌寫入器(LGWR)進程寫入的,而是由新的叫做恢復寫入器的進程(RVWR)負責。不像常規的重做日誌,閃回日誌文件不需要DBA來創建和維護,它們由Oracle Managed Files(OMF)自動在指定的閃回恢復區中創建,他們不會被歸檔。


Flashback操作

在上面所描述的頂點銀行的例子中,約翰確定閃回表是不可行的,他需要把整個數據庫回滾到過去的某個時點。他選擇了11:00p.m作爲起點並執行了下面的命令:
flashback database to timestamp
to_timestamp ('12/31/2003
23:00:00','mm/dd/yyyy hh24:mi:ss');
這個操作執行了所有需要的工作,比如利用閃回恢復區的信息恢復數據文件。整個數據庫被恢復到了11:00p.m的狀態,約翰不需要執行任何手工恢復操作。除了使用時間戳,還可以使用SCN來閃回。在警告日誌中會記錄所執行的閃回操作。
儘管數據庫被恢復到了11:00p.m,問題是,它是不是正確的時間呢?約翰使用了和先前一樣的參考點技術。他以只讀的方式打開數據庫並查詢賬戶的狀態:
alter database open read only;

select status, count(*)
from BANK.ACCOUNTS
group by status;

STATUS COUNT(*)
------ --------
I 255
F 46832
答案是否定的,仍然有255條記錄的狀態爲"I",他需要閃回到更早的時間,比如10:30p.m.,如下:
shutdown immediate
startup mount

flashback database to timestamp
to_timestamp ('12/31/2003 22:30:00,
'mm/dd/yyyy hh24:mi:ss');

alter database open read only;
在ACCOUNTS表上執行同樣的查詢:
select status, count(*)
from BANK.ACCOUNTS
group by status;
他發現所有的賬戶狀態都是"A",意思是他閃回的太遠啦,把數據庫閃回到更近的狀態,比如10:45p.m.,如下:
shutdown immediate
startup mount

flashback database to timestamp
to_timestamp ('12/31/2003 22:45:00,
'mm/dd/yyyy hh24:mi:ss');

alter database open read only;
現在再次查詢狀態:
select status, count(*)
from bank.accounts
group by status;
所有的賬戶狀態都是"F",正是我們需要的。現在,約翰把數據庫恢復到了他需要的狀態,他可以打開數據庫並執行所需的更新了:
shutdown immediate
startup mount
alter database open resetlogs;
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章