使用控制程式碼實現特定場景的無備份恢復

dbhelper發表於2014-11-26
在dba的工作中,備份是一切工作的基礎。如果沒有備份,本來很簡單的恢復工作也會難上加難,如果業務資料要求很高,造成資料的丟失或者損壞,就是重大事故了。
使用rman備份或者做一個完整的系統級備份也是很重要的,如果在特定的場景下,沒有備份,如果還能恢復,那就太幸運了。
當資料庫中的某個資料檔案誤刪的時候,如果資料庫還沒有重啟的時候,還是能夠做一些工作的。因為檔案對應的控制程式碼還沒有釋放。我們可以從裡面找到一個映象的備份實現我們的資料恢復。一定注意這種恢復不一定是完全的資料恢復,如果在資料檔案刪除的瞬間,有開啟的事務,那麼這些事務也是提交過的。
在刪除之前,我們先來看看測試環境的資料檔案情況。
SQL> select tablespace_name,file_name from dba_data_files;
TABLESPACE_NAME                FILE_NAME
------------------------------ --------------------------------------------------
SYSTEM                         /u03/ora11g/oradata/TEST01/system01.dbf
SYSAUX                         /u03/ora11g/oradata/TEST01/sysaux01.dbf
UNDOTBS                        /u03/ora11g/oradata/TEST01/undotbs01.dbf
TEST_DATA1                     /u02/ora11g/testdata1.dbf
POOL_DATA                      /u03/ora11g/oradata/TEST01/pool_data03.dbf
POOL_DATA                      /u03/ora11g/oradata/TEST01/pool_data01.dbf
POOL_DATA                      /u03/ora11g/oradata/TEST01/pool_data02.dbf
POOL_DATA                      /u03/ora11g/oradata/TEST01/pool_data04.dbf
POOL_DATA                      /u03/ora11g/oradata/TEST01/pool_data05.dbf
POOL_DATA                      /u01/ora11g/pool_data06.dbf
POOL_DATA                      /u01/ora11g/pool_data07.dbf
11 rows selected.
我們建立一個新的表空間和資料檔案,

SQL> create tablespace test_delete datafile '/u01/ora11g/test_delete.dbf' size 10M;
Tablespace created.

SQL> create user test_delete identified by test_delete default tablespace test_delete quota unlimited on test_delete;
User created.
然後建立一個使用者,在裡面新增一些資料。
grant connect,resource to test_delete;
conn test_delete/test_delete
create table test as select *from all_objects;
create index test_ind on test(object_id);
create table test1 as select *from test where rownum<100;
update test1 set object_name='a' ;
注意最後的一條update語句,我們還沒有做commit操作,所以此時資料還可能沒有寫入資料檔案,從事務的角度來說,這個update還沒有完成。
我們來看看是否能夠恢復所有的資料,包括未提交的事務資料。

在刪除之前,簡單來一個檢查。

SQL> select count(*)from test;
  COUNT(*)
----------
      5660

SQL> select count(*)from test1 where object_name='a';
  COUNT(*)
----------
        99
開始手動刪除資料檔案

[ora11g@rac1 fd]$ rm /u01/ora11g/test_delete.dbf
刪除之後嘗試做一個create操作,竟然成功了。

SQL> create table test3 as select *from test1;
Table created.
繼續嘗試一個Update,終於報錯了,得到了期望之中的Ora錯誤。
update test set object_id=1
       *
ERROR at line 1:
ORA-01116: error in opening database file 12
ORA-01110: data file 12: '/u01/ora11g/test_delete.dbf'
ORA-27041: unable to open file
Linux-x86_64 Error: 2: No such file or directory
Additional information: 3
這個時候開始考慮使用控制程式碼來檢視對應的資料檔案,
首先使用ps得到dbw對應的程式號。

[ora11g@rac1 proc]$ ps -ef|grep ora_dbw
ora11g     938     1  0 Nov20 ?        00:00:07 ora_dbw0_TEST01
ora11g    7819  5794  0 06:04 pts/0    00:00:00 grep ora_dbw

然後在/proc/938/fd裡面檢視
[ora11g@rac1 proc]$ ll /proc/938/fd   
total 0
lr-x------ 1 ora11g dba 64 Nov 21 05:36 0 -> /dev/null
l-wx------ 1 ora11g dba 64 Nov 21 05:36 1 -> /dev/null
lr-x------ 1 ora11g dba 64 Nov 21 05:36 10 -> /dev/zero
lr-x------ 1 ora11g dba 64 Nov 21 05:36 11 -> /dev/zero
lrwx------ 1 ora11g dba 64 Nov 21 05:36 12 -> /u03/ora11g/product/11.2.0/dbhome_1/dbs/hc_TEST01.dat
lr-x------ 1 ora11g dba 64 Nov 21 05:36 13 -> /u03/ora11g/product/11.2.0/dbhome_1/rdbms/mesg/oraus.msb
lr-x------ 1 ora11g dba 64 Nov 21 05:36 14 -> /proc/938/fd
lr-x------ 1 ora11g dba 64 Nov 21 05:36 15 -> /dev/zero
lrwx------ 1 ora11g dba 64 Nov 21 05:36 16 -> /u03/ora11g/product/11.2.0/dbhome_1/dbs/hc_TEST01.dat
lrwx------ 1 ora11g dba 64 Nov 21 05:36 17 -> /u03/ora11g/product/11.2.0/dbhome_1/dbs/lkTEST01
lr-x------ 1 ora11g dba 64 Nov 21 05:36 18 -> /u03/ora11g/product/11.2.0/dbhome_1/rdbms/mesg/oraus.msb
lrwx------ 1 ora11g dba 64 Nov 21 06:05 19 -> socket:[1434598]
l-wx------ 1 ora11g dba 64 Nov 21 05:36 2 -> /dev/null
lrwx------ 1 ora11g dba 64 Nov 21 05:36 256 -> /u03/ora11g/oradata/TEST01/control01.ctl
lrwx------ 1 ora11g dba 64 Nov 21 05:36 257 -> /u03/ora11g/oradata/TEST01/control02.ctl
lrwx------ 1 ora11g dba 64 Nov 21 05:36 258 -> /u03/ora11g/oradata/TEST01/system01.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 259 -> /u03/ora11g/oradata/TEST01/sysaux01.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 260 -> /u03/ora11g/oradata/TEST01/undotbs01.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 261 -> /u02/ora11g/testdata1.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 262 -> /u03/ora11g/oradata/TEST01/pool_data03.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 263 -> /u03/ora11g/oradata/TEST01/pool_data01.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 264 -> /u03/ora11g/oradata/TEST01/pool_data02.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 265 -> /u03/ora11g/oradata/TEST01/pool_data04.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 266 -> /u03/ora11g/oradata/TEST01/pool_data05.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 267 -> /u01/ora11g/pool_data06.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 268 -> /u01/ora11g/pool_data07.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:36 269 -> /u03/ora11g/oradata/TEST01/temp01.dbf
lrwx------ 1 ora11g dba 64 Nov 21 05:55 270 -> /u01/ora11g/test_delete.dbf (deleted)
lr-x------ 1 ora11g dba 64 Nov 21 05:36 3 -> /dev/null
lr-x------ 1 ora11g dba 64 Nov 21 05:36 4 -> /dev/null
lr-x------ 1 ora11g dba 64 Nov 21 05:36 5 -> /dev/null
lr-x------ 1 ora11g dba 64 Nov 21 05:36 6 -> /dev/null
lrwx------ 1 ora11g dba 64 Nov 21 05:36 7 -> /u03/ora11g/product/11.2.0/dbhome_1/dbs/hc_TEST01.dat
lr-x------ 1 ora11g dba 64 Nov 21 05:36 8 -> /dev/null
lr-x------ 1 ora11g dba 64 Nov 21 05:36 9 -> /dev/null

可以看到控制程式碼的資訊,刪除的資料檔案狀態已經在/proc/xx/fd裡面有所體現了。
這個時候我們手動複製資料檔案到目標目錄。

[ora11g@rac1 fd]$ cp 270 /u01/ora11g/test_delete.dbf
[ora11g@rac1 fd]$
複製完成之後,使用測試使用者來做一些簡單的驗證。發現建立一個新表的操作順利完成了。

SQL> conn test_delete/test_delete
Connected.
SQL> create table test4 as select *from cat;
Table created.
來看看在資料檔案恢復之前的情況。
SQL> select count(*)from test;  --資料沒有問題,條數和預期一致。
  COUNT(*)
----------
      5660

SQL> select count(*)from test1 where object_name='a';  --這個部分,事務已經做了提交。可以說明變更的資料已經寫入了資料檔案。期望應該是0條。
  COUNT(*)
----------
        99


然後我們來嘗試做資料檔案的恢復。

SQL> conn / as sysdba
Connected.
SQL> alter database datafile '/u01/ora11g/test_delete.dbf' offline;
Database altered.
SQL> recover datafile '/u01/ora11g/test_delete.dbf';
Media recovery complete.
SQL> alter database datafile '/u01/ora11g/test_delete.dbf' online;
Database altered.
來看看資料檔案恢復之後的情況

SQL> select count(*)from test;  --資料沒有問題,條數和預期一致。
  COUNT(*)
----------
      5660

SQL> select count(*)from test1 where object_name='a';  --這個部分,事務已經做了提交。可以說明變更的資料已經寫入了資料檔案。期望應該是0條。
  COUNT(*)
----------
        99

重新啟動資料庫來看看能否正常啟停。資料的變化情況。
SQL> shutdown immediate
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL> startup
ORACLE instance started.

Total System Global Area  313159680 bytes
Fixed Size                  2227944 bytes
Variable Size             255852824 bytes
Database Buffers           50331648 bytes
Redo Buffers                4747264 bytes
Database mounted.
Database opened.

SQL> conn test_delete
Enter password:
Connected.
SQL> select count(*)from test;  --資料沒有問題,條數和預期一致。
  COUNT(*)
----------
      5660

SQL> select count(*)from test1 where object_name='a';  --這個部分,事務已經做了提交。可以說明變更的資料已經寫入了資料檔案。期望應該是0條。
  COUNT(*)
----------
        99

所以透過上面的例子也能夠說明備份重於一切,而且這種恢復還是需要運氣的,不過某正程度來說,有總比沒有好。而且這種恢復也是需要運氣,如果資料庫一開始停掉的話,也無能為力了。

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

相關文章