Oracle數據誤刪恢復機制

Oracle數據庫在多版本數據管理的設計是非常優秀的,數據的誤刪恢復非常簡單。除了truncate以外,drop table語句和所有DML語句都是可以輕鬆恢復。

恢復DROPED TABLE


Oracle和windows類似,也有個‘回收站’的概念,查看回收站的方法很多,例如user_recyclebin系統視圖是比較常用的,該視圖中的內容包括(恢復操作所需要的):

  • 被刪除的表在回收站中叫什麼名字(OBJECT_NAME)
  • 被刪除的表原來叫什麼名字(ORIGINAL_NAME)
  • 表是什麼時候被刪除的(DROPTIME)
desc user_recyclebin;

名稱             空值?      類型           
-------------- -------- ------------ 
OBJECT_NAME    NOT NULL VARCHAR2(30) 
ORIGINAL_NAME           VARCHAR2(32) 
OPERATION               VARCHAR2(9)  
TYPE                    VARCHAR2(25) 
TS_NAME                 VARCHAR2(30) 
CREATETIME              VARCHAR2(19) 
DROPTIME                VARCHAR2(19) 
DROPSCN                 NUMBER       
PARTITION_NAME          VARCHAR2(32) 
CAN_UNDROP              VARCHAR2(3)  
CAN_PURGE               VARCHAR2(3)  
RELATED        NOT NULL NUMBER       
BASE_OBJECT    NOT NULL NUMBER       
PURGE_OBJECT   NOT NULL NUMBER       
SPACE                   NUMBER       
  • 示例:

先簡單創建一張測試表,然後刪除

SQL> conn test/test
Connected.
SQL> create table mytbl as select 1 as flag from dual;

Table created.

SQL> select * from mytbl;

      FLAG
----------
     1

SQL> drop table mytbl;

Table dropped.

然後可以在user_recyclebin中找到我們剛纔刪除的表

SQL> col object_name for a30
SQL> col original_name for a30
SQL> col droptime for a30
SQL> set linesize 1000
SQL> select object_name,original_name,droptime from user_recyclebin;

OBJECT_NAME            ORIGINAL_NAME              DROPTIME
------------------------------ ------------------------------ ------------------------------
BIN$ksxWUEIJRM3gUADAhgIE7Q==$0 MYTBL                  2019-09-17:23:21:47

可以使用OBJECT_NAME來查看錶中的數據,OBJECT_NAME是由系統自動生成的名字,需要用雙引號“”才能被識別爲表名。

SQL> select * from "BIN$ksxWUEIJRM3gUADAhgIE7Q==$0";

      FLAG
----------
     1

接下來就可以用flashback table to before dropflashback table to before drop rename to命令將表找回或重命名爲新的表名

SQL> flashback table "BIN$ksxWUEIJRM3gUADAhgIE7Q==$0" to before drop;

Flashback complete.

SQL> select * from mytbl;

      FLAG
----------
     1

SQL> select * from user_recyclebin;

no rows selected

flashback table “XXX” to before drop rename to XXX命令可以將表命名爲新的名字,而非ORIGINAL_NAME。恢復之後,回收站中該對象就看不到了。

由此我們可以看出,所謂的DROP TABLE表刪除本質上僅僅是將表重命名爲新的名字,而非物理清除。如果想物理清除需要使用PURGE關鍵字。

SQL> drop table mytbl purge;

Table dropped.

SQL> select * from user_recyclebin;

no rows selected

當然,被刪除的表不可能永遠保留,保留的時間和表空間的剩餘空間有關,當剩餘表空間不足時,則回收站裏的對象會被清理掉,優先清理最早放進回收站的(DROPTIME最小的)。

恢復CHANGED ROWS


和被刪除的表類似,被DML語句修改的行,也會在數據庫中保留一段時間,保留時間長短和UNDO的保留策略以及UNDO的實際使用情況有關,稍後會更詳細講解。先來看看如何對已經提交的DML語句影響的行恢復到語句執行之前的狀態(未提交的直接執行rollback即可)。

方法一:VERSIONS BETWEEN
  • 示例:

模擬誤刪場景,先查看一下EMP表中的數據,然後刪除表中的一行並提交,

SQL> conn scott/tiger
Connected.
SQL> set linesize 1000
SQL> set pagesize 1000
SQL> select * from emp;

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300     30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500     30
      7566 JONES      MANAGER         7839 02-APR-81       2975            20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400     30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850            30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450            10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000            20
      7839 KING       PRESIDENT        17-NOV-81       5000            10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500      0     30
      7876 ADAMS      CLERK       7788 23-MAY-87       1100            20
      7900 JAMES      CLERK       7698 03-DEC-81        950            30
      7902 FORD       ANALYST         7566 03-DEC-81       3000            20
      7934 MILLER     CLERK       7782 23-JAN-82       1300            10

14 rows selected.

SQL> delete from emp where empno = 7369;

1 row deleted.

SQL> commit;

Commit complete.

SQL> select * from emp where empno = 7369;

no rows selected

利用VERSIONS子句查看被刪除的行相關的信息

SQL> select * from emp versions between scn minvalue and maxvalue where empno = 7369;

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20
      7369 SMITH      CLERK       7902 17-DEC-80        800            20

我們明明只刪了一行,爲什麼查詢的結果中有兩行呢?加上versions between scn minvalue and maxvalue關鍵字後,實際上是顯示了表上數據行所有變化的“流水賬”,準確的說,並非所有變化,而是UNDO保留時間窗口內記錄的所有”流水賬“加上表在UNDO保留時間窗口的起始時間點的靜態版本。比如,undo_retention參數設置成了3600,表示這個保留時間窗口爲1小時(3600s),那麼versions子句所能看到的數據爲:表在一小時前那個時間點的靜態版本+這一小時內的所有的變化流水。

流水記錄中的內容除了包括數據行內容本身以外,還包括這一行上發生的具體操作是什麼(versions_operation輔助隱藏列,D表示delete,I表示insert,U表示update),操作發生的時間是什麼(導致該行發生變化的操作何時開始versions_startscn,該行再次發生變化的時間即該行不再是最新行版本的時間versions_endscn,SCN是數據庫隨時間單調遞增的系統變更號,可以理解爲時間)

SQL> col versions_startscn for 99999999999999
SQL> col versions_endscn for 99999999999999
SQL> col versions_operation for a30

SQL> select versions_operation,versions_startscn,versions_endscn,t.empno 
   from emp versions between scn minvalue and maxvalue t;  

VERSIONS_OPERATION   VERSIONS_STARTSCN VERSIONS_ENDSCN        EMPNO
-------------------- ----------------- --------------- ------------
D                     145852760112                            7369
                                         145852760112         7369
                                                              7499
                                                              7521
                                                              7566
                                                              7654
                                                              7698
                                                              7782
                                                              7788
                                                              7839
                                                              7844
                                                              7876
                                                              7900
                                                              7902
                                                              7934

15 rows selected.

這樣我們就能清楚地區分出EMPNO=7369的兩行當中,versions_operation='D'的那一行是我們剛纔刪除的那一行,而另一行的versions_operation is null表示該行爲初始版本(UNDO保留最早時間點的數據版本),由於被delete之前,改行沒有其他操作,實際上兩行的數據部分完全一致,恢復時只需要對查詢結果去重即可,或者添加versions_operation = 'D'條件

現在我們開始恢復:

SQL> insert into emp select * from emp versions between scn minvalue and maxvalue where versions_operation = 'D' and empno = 7369;

1 rows inserted.

commit;
方法二:FLASHBACK
  • 原理簡單介紹:

Oracle FLASHBACK TABLE 功能同樣是利用了UNDO“記流水賬”的功能,但FLASHBACK TABLE TO BEFORE DROP不是,前面已經說了,這是使用了“回收站”的原理。回收站純粹是爲了防誤刪而設計的,而UNDO除了誤刪恢復以外,還有其他更重要的意義——UNDO和事務的一致性和隔離性息息相關、事務的回滾(rollback命令或事務的異常終止)和一致性讀需要UNDO。這裏給大家簡單科普一下UNDO的大致作用,若當前會話上的事務對數據進行了修改,在執行提交之前,其他的會話不應該看到當前會話修改後的內容(事務隔離性),但數據又的確是修改了,只是沒有提交,因此需要UNDO來實現其他會話看到當前會話修改之前的數據版本,UNDO具有這種記流水賬的功能,因此具備提供時間窗口內任意一個時間點的數據版本的能力。

  • 示例:

查看數據,然後刪除一行,刪除之前查看一下時間,主要是爲了記錄一個誤刪之前的時間點,後續恢復需要用到這個時間。這種方法相對於versions方法的侷限性在於需要回憶起誤刪操作的大致時間範圍。

SQL> conn scott/tiger
Connected.
SQL> set linesize 1000
SQL> set pagesize 1000
SQL> select * from emp;

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300     30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500     30
      7566 JONES      MANAGER         7839 02-APR-81       2975            20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400     30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850            30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450            10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000            20
      7839 KING       PRESIDENT        17-NOV-81       5000            10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500      0     30
      7876 ADAMS      CLERK       7788 23-MAY-87       1100            20
      7900 JAMES      CLERK       7698 03-DEC-81        950            30
      7902 FORD       ANALYST         7566 03-DEC-81       3000            20
      7934 MILLER     CLERK       7782 23-JAN-82       1300            10

14 rows selected.

SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss')  as cur_date from dual;

CUR_DATE
-------------------
2019-09-19 02:07:15

SQL> delete from emp where empno = 7369;

1 row deleted.

SQL> commit;

SQL> select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') as cur_date from dual;

CUR_DATE
-------------------
2019-09-19 02:08:29

SQL> select * from emp where empno = 7369;

no rows selected

使用as of timestamp子句查看指定時間點的數據版本

SQL> select * from emp as of timestamp to_timestamp('2019-09-19 02:07:15','yyyy-mm-dd hh24:mi:ss');

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300     30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500     30
      7566 JONES      MANAGER         7839 02-APR-81       2975            20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400     30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850            30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450            10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000            20
      7839 KING       PRESIDENT        17-NOV-81       5000            10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500      0     30
      7876 ADAMS      CLERK       7788 23-MAY-87       1100            20
      7900 JAMES      CLERK       7698 03-DEC-81        950            30
      7902 FORD       ANALYST         7566 03-DEC-81       3000            20
      7934 MILLER     CLERK       7782 23-JAN-82       1300            10

14 rows selected.

SQL> select * from emp as of timestamp to_timestamp('2019-09-19 02:07:15','yyyy-mm-dd hh24:mi:ss') where empno = 7369;

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20

然後開始恢復,可以直接將as of timestamp語句(閃回查詢)查到的誤刪行insert回去,也可以用flashback table to timestamp語句進行閃回操作。

SQL> flashback table emp to timestamp to_timestamp('2019-09-19 02:07:15','yyyy-mm-dd hh24:mi:ss');

Flashback complete.

SQL> select * from emp;

     EMPNO ENAME      JOB          MGR HIREDATE     SAL       COMM     DEPTNO
---------- ---------- --------- ---------- --------- ---------- ---------- ----------
      7369 SMITH      CLERK       7902 17-DEC-80        800            20
      7499 ALLEN      SALESMAN        7698 20-FEB-81       1600        300     30
      7521 WARD       SALESMAN        7698 22-FEB-81       1250        500     30
      7566 JONES      MANAGER         7839 02-APR-81       2975            20
      7654 MARTIN     SALESMAN        7698 28-SEP-81       1250       1400     30
      7698 BLAKE      MANAGER         7839 01-MAY-81       2850            30
      7782 CLARK      MANAGER         7839 09-JUN-81       2450            10
      7788 SCOTT      ANALYST         7566 19-APR-87       3000            20
      7839 KING       PRESIDENT        17-NOV-81       5000            10
      7844 TURNER     SALESMAN        7698 08-SEP-81       1500      0     30
      7876 ADAMS      CLERK       7788 23-MAY-87       1100            20
      7900 JAMES      CLERK       7698 03-DEC-81        950            30
      7902 FORD       ANALYST         7566 03-DEC-81       3000            20
      7934 MILLER     CLERK       7782 23-JAN-82       1300            10

14 rows selected.

兩種方法的區別和優缺點總結:

versions方法受限於undo_retention參數,時間窗口會隨着時間不段向後推進,若undo_retention設置過小,則很快就沒法查到變化記錄,不過可以臨時調大參數來滿足查詢,優點是可以查到所有行的修改操作記錄,缺點是比較複雜,不太直觀。FLASHBACK方法則可以查到UNDO中實際存在的所有數據版本,和undo_rentention參數無關,UNDO保留的機制和回收站類似,取決於UNDO表空間的剩餘大小,還受到相關參數的影響,flashback table方法的優點是便捷、直觀,缺點是需要找到相對準確的時間點。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章