Oracle數據庫數據丟失?這幾種方法教你來恢復~
無論是開發、測試還是運維過程中,大家都可能會因為誤操作、連錯數據庫、用錯用戶、語句條件有誤等原因,導致錯誤刪除、錯誤更新等問題。當你恨不得剁掉按回車的那個指頭、捶胸頓足、或者嚇得腿軟時,肯定希望有辦法來恢復這些數據。剛好,oracle 提供了一些強大的方法或機制,可以讓你找到 “后悔藥”。
根據 oracle 數據庫的特點和提供的工具,主要方法有以下幾種方法:
- 利用邏輯備份使用 import 工具丟失數據的表
- 利用物理備份來通過還原數據文件并進行不完全恢復
- 利用 dbms_logmnr 包從 redo log 文件中恢復
- 利用 flashback 特性恢復數據
為了方便使用方法的介紹,上述恢復方法都將基于以下場景進行:系統管理員在前一天晚上 11 點用 export 對數據庫做了全庫邏輯備份,然后對所有數據文件進行了熱備份。第二天上午 10 點,系統管理員在修改表 TFUNDASSET 的數據時,由于修改語句的條件寫錯了,導致一批記錄(幾千條)的 ztm 字段被修改成了錯誤的值,而且已經提交。這個表是資產表,相對而言數據變化不頻繁。
一、利用邏輯備份使用 import 工具恢復丟失的數據
export/import 是 oracle 提供的用于對數據庫進行邏輯備份的工具。該工具適用于備份那些數據量不大、業務量不多的數據庫系統。因為如果在前一天晚上 11 點用 export 做了邏輯備份,那么當今天上午 10 點數據庫意外崩潰時,從備份起到數據庫崩潰的這段時間里的數據修改操作(包括 DDL 和 DML)都會丟失。如果丟失數據內的表上的數據是相對比較穩定,也就是說該表上基本沒有 DML 操作,例如標準代碼表、分區表里的歷史數據,那么采用 import 來導入該表可以比較完整的恢復數據。如果該表是經常變化的業務表,那么這些丟失的數據只能根據業務情況從紙質記錄恢復,或者其他途徑恢復。
▲示例如下:這個表是一個資產表。相對來說,今天系統運行中修改的數據較少,丟失的數據量可以承受或者可以從別的途徑恢復。那就可以用 import 來恢復。
方法一:
1、把這個表的數據備份到另一個表:
2、刪除該表的記錄:
3、執行下面的命令:
這個命令中在關鍵字 tables 中指定需要導入的表名字,ignore=y 表示忽略表已經存在的錯誤。
4、導入結束后,檢查表中的記錄,并用適當的方法恢復當天的修改。
方法二:
1、 把需要恢復的表導入到另一個用戶下面:
2、檢查數據以后,把原表記錄刪除:
3、然后從另一用戶表中插入回去:
4、 數據量比較大時可以采用如下方法:
二、利用物理備份來通過還原數據文件并進行不完全恢復
如果數據庫運行在歸檔模式下,那么可以通過使用以前的數據文件備份進行還原,然后利用歸檔日志進行前滾,直到回滾到錯誤操作的時間點前,然后重置日志文件打開數據庫。
可以通過下列方法確認是否是運行在歸檔模式:
如果是如上所示,那么就是運行在歸檔模式了。
▲假定在前一天晚上 11 點做了全庫物理備份,那么可以考慮如下恢復:
1、關閉數據庫:
由于數據庫的不完全恢復必須在一個關閉的數據庫上實施,利用一個舊的數據庫的備份還原,然后用日志根據需要逐步前滾,而不能還原一個新的備份,再回退到某個時間點。
通知各客戶端數據庫將關閉,然后發出:
數據庫已經關閉。
已經卸載數據庫。
ORACLE 例程已經關閉。
2、確定錯誤操作的時間:
可以根據操作員的估計來確定不完全恢復需要前滾停止的時間,也可以利用 LogMiner 來分析日志文件(這個工具將在后面介紹),找出錯誤操作的準確時間。
3、還原數據文件:
先對當前的數據庫文件進行備份,然后再用以前的最近一次備份覆蓋現有數據文件。注意:不覆蓋現有的控制文件。
4、基于時間點恢復,啟動數據庫到裝配狀態:
這樣數據庫就恢復到了 2015 年 10 月 20 日的 9 點 58 分零秒。
然后再利用業務資料補充這段時間內的數據。
三、利用 dbms_logmnr 包從 log 文件中恢復
這個包是由 Oracle 提供,與 dbms_logmnr_d 包配合使用可以方便地分析聯機日志文件和歸檔日志文件,從這些日志文件中提取出所有對數據庫的更改操作。
在使用這個包之前,需要先做一些設置和修改:
1、打開 initorcl.ora,修改初始化參數 utl_file_dir,設置 dbms_logmnr_d 包將要使用的數據字典文件的放置目錄。
然后重啟數據庫使參數生效。
2、以 sys 用戶連接到數據庫執行 dbmslmd.sql 腳本重建 dbms_logmnr_d 這個包。
應用 Logminer 分析重做日志文件的操作主要有以下步驟:
- 使用 dbms_logmnr_d 里的存儲過程 build 創建一個外部數據字典文件;
- 使用 dbms_logmnr 里的存儲過程 add_logfile 添加要分析的日志文件;
- 使用 dbms_logmnr 里的存儲過程 start_logmnr 啟動分析;
- 查詢與 dbms_logmnr 相關的幾個視圖來獲取日志文件內容;
- 使用 dbms_logmnr 里的存儲過程 end_logmnr 結束分析。
▲下面詳細講述使用的過程
1)使用 dbms_logmnr_d 里的存儲過程 build 創建一個外部數據字典文件:
2)使用 dbms_logmnr 里的存儲過程 add_logfile 添加要分析的日志文件到待分析文件列表:
如果沒有運行在歸檔模式,那么由于重做日志文件的循環使用可能導致日志文件被覆蓋而無法獲取到所要尋找的恢復條目。如果運行在歸檔模式,則可以通過查看 $ORACLE_HOME\admin\orcl\bdump 目錄下的 alert_orcl.log 里日志文件歸檔的時間和錯誤操作的時間來確定加入哪些歸檔日志文件到待分析的文件列表中去。
注意:執行以上過程時 logfilename 參數需要寫日志文件的全路徑,否則會報錯。重復以上操作直到把所有需要分析的文件都加到列表中去。這樣就可以啟動進行分析。
3)使用 dbms_logmnr 里的存儲過程 start_logmnr 啟動分析;
這樣就可以通過下面的查詢來獲取日志文件的內容了。
4)查詢與 dbms_logmnr 相關的幾個視圖來獲取日志文件內容;
這樣就可以找出要恢復所需的語句。注意:v$logmnr_contents 只對執行 dbms_logmnr.start_logmnr 的會話有效,如果通過其他會話或者使用 dbms_logmnr.end_logmnr 終止了分析,都將不能訪問 v$logmnr_contents 的數據。如果要使其他會話也能獲取到這些數據,可以通過另外建表來實現,如:
create table undo_sql as select * from v$logmnr_contents。
再對 undo_sql 進行授權,其他用戶就可以訪問 v$logmnr_contents 的數據了。
5)使用 dbms_logmnr 里的存儲過程 end_logmnr 結束分析。
使用完成以后用下面的命令來結束分析活動:exec dbms_logmnr.end_logmnr;
這樣就釋放了分配給 logminer 的資源(內存和數據結構)。
從上面的過程可知,如果是更新的數據量比較大,而日志文件比較小,就可能會導致日志文件的切換。如果沒有及時去挖掘日志文件(沒有運行在歸檔模式),那么可能會由于日志文件的循環使用而導致數據不可恢復。如果運行在歸檔模式,也可能由于需要分析的日志文件比較多而時間較長。
四、利用 flashback 新特性恢復數據
Oracle9i 開始提供了閃回查詢(Flashback Query)功能,對于誤刪除或者誤更新并且已經 commit 了的情況提供了簡便快捷的恢復方法;而在 Oracle 提供閃回查詢之前,碰到這種情況只能通過備份來進行基于時間點的恢復或者使用 logmnr 挖掘日志來恢復,無疑這比閃回查詢要麻煩而且費時。
使用這個 Flashback Query 特性的前提條件:
1. 數據庫必須處于 Automatic Undo Management 狀態。
2. ***可以閃回查詢的時間段由 UNDO_RETENTION 初始化參數(單位為秒)指定
可以通過 ALTER SYSTEM SET UNDO_RETENTION = <seconds>; 來動態修改參數值。
▲如何使用 Flashback Query 來恢復數據呢?
1)通過 SQL
使用 SELECT 語句的 AS OF 來進行閃回查詢,語法如下:
使用 AS OF 關鍵字來對表,視圖或者物化視圖進行 Flashback Query,如果指定了 SCN,那么 expr 部分必須是一個數字,如果指定了 TIMESTAMP,那么 expr 必須是一個 timestamp 類型的值。查詢結果將返回在指定的 SCN 或者時間點上的數據。
下面我們使用 scott 方案來作一個實驗。
如果想在 update 的子查詢部分使用 AS OF,那么該查詢只能返回一條記錄,否則將會報錯。
可以通過添加一個臨時表作為中轉,然后再作更新,如下:
2)通過 DBMS_FLASHBACK 包來恢復
DBMS_FLASHBACK 包提供了以下幾個函數:
- ENABLE_AT_TIME:設置當前 SESSION 的閃回查詢時間
- ENABLE_AT_SYSTEM_CHANGE_NUMBER:設置當前 SESSION 的閃回查詢 SCN
- GET_SYSTEM_CHANGE_NUMBER:取得當前數據庫的 SCN
- DISABLE:關閉當前 SESSION 的閃回查詢
當將一個 SESSION 設置為閃回查詢模式之后,后續的查詢都會基于那個時間點或者 SCN 的數據庫狀態,如果 SESSION 結束,那么即使沒有明確指定 DISABLE,閃回查詢也會自動失效。
當 SESSION 運行在閃回查詢狀態時,不允許進行任何 DML 和 DDL 操作。如果要用 DML 操作來進行數據恢復就必須使用 PL/SQL 游標。
▲示例:
通過上面的例子可以看出,只要這個修改的時間不早于 sysdate- (UNDO_RETENTION 指定的秒數), 就可通過這種方式來恢復數據。
對于問題中的批量數據,可以寫個過程來完成獲取到更改前的數據:
然后再用這個臨時表里的數據來更新 TFUNDASSET 就可以了。
五、總結
比較以上幾種恢復數據的方法的使用過程,我們可以看出:
- exp/imp 只適合于數據變化不大的表的數據丟失的情況,即使用這種方法處理后也需要從業務辦理資料中修正數據,否則導致數據丟失;
- 采用基于時間點的不完全恢復可以恢復丟失的數據,但是需要關關閉數據庫,減少系統可用時間,而且也會丟失恢復時間點以后的數據;
- 使用 LogMiner 可以較好的恢復數據,但是要求數據庫盡可能運行在歸檔模式,否則也可能導致數據丟失。好處是不用關閉系統,能夠從日志文件中得到所有的數據。
- 使用 Flashback 最方便和簡潔,可以直接得到修改前的數據,但是需要依賴系統設置,并且需要占用大量的回滾表空間。
因此選擇什么樣的方法來恢復數據,取決于你的系統環境和具體情況,不能生搬硬套。采用正確的方法才能***程度的減少數據的丟失。
當然,***是不需要用到這些恢復的辦法。前提是,你必須做好以下的工作:
- 為不同環境創建不同的數據庫用戶、不同密碼(如果不能用戶不同,一定要密碼不同);
- 將 owner 和應用用戶分開,并做適度授權;
- 在做 DML 前,先用同樣的條件做查詢,看根據結果集是否符合預期。