flashback query恢复dml误操作数据

利用flashback query恢复dml误操作数据

1使用闪回查询前必须确定下面两个参数

UNDO_MANAGEMENT = AUTO

undo_retention = 1800;   #这个时间可以随便设,他表示在系统中保留提交了的UNDO信息的时间,1800就是保留30分钟。

 

select dbms_flashback.get_system_change_number from dual;  ----获取当前scn

 SQL> select scn_to_timestamp(2599788) from dual;    ----scn转为时间

SQL>select timestamp_to_scn(to_timestamp('2016-5-1 6:06:06','yyyy-mm-dd hh24:mi:ss')) FROM dual;                   ----将时间转为scn

 

2环境准备(9i)

1)查看数据库模式

SQL> archive log list

数据库日志模式             非存档模式

自动存档             禁用

存档终点            C:\oracle\ora92\RDBMS

最早的概要日志序列     1

当前日志序列           2

SQL> select log_mode,open_mode from v$database;

LOG_MODE     OPEN_MODE

------------ ----------

NOARCHIVELOG READ WRITE

2)创建闪回用户

SQL> create user shallzhong identified by shall;

用户已创建

SQL> grant connect,resource to shallzhong;

授权成功。

SQL> grant execute on dbms_flashback to shallzhong;

授权成功。

SQL> conn shallzhong/shall

已连接。

3)创建测试表,并插入数据提交

SQL> create table zhong(id int,name varchar2(10));

表已创建。

 

SQL> begin

  2  for i in 1..100001 loop

  3  insert into zhong values(i,'zhong');

  4  end loop;

  5  commit;

  6  end;

  7  /

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

    100001

4)记录删除之前时间或SCN

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

TO_CHAR(SYSDATE,'YY

-------------------

2016-05-14 11:30:56

select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

                  275829

记录时间后,最好等一段时间在做下面的操作,oracle5分钟才记录一次scn,所以可能会导致闪回查询不到数据

5)删除数据并提交

SQL> delete zhong;

已删除100001行。

 

SQL> commit;

提交完成。

3闪回查询(9i

SQL> execute dbms_flashback.enable_at_time(to_date('2016-05-14 11:30:56','yyyy-mm-dd hh24:mi:ss'));

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

         0

 

SQL> execute dbms_flashback.disable;

PL/SQL 过程已成功完成。

 

SQL> execute dbms_flashback.enable_at_system_change_number(275829);

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

    100001

 

SQL> execute dbms_flashback.disable;

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

         0

1)为什么基于时间闪回查询不到数据?而基于scn可以?

    闪回查询是基于SCN的:(oracle9i中smon_scn_time表每5分钟被更新一次,oracle10g是每6秒更新一次)

    Oracle并不会精确的这个时间点,进行恢复。而Oracle 9i是每五分钟记的而是ROUND DOWN到最近的一次SCN,然后从这个SCN开始记录一次SCN,并将SCN和对应时间的映射做个纪录。这正是上面进行dbms_flashback.enable_at_time查询不到删除数据的原因。所以,删除之前等5分钟试试最保险。

      select * from smon_scn_time;

    SMON_SCN_TIME记录5天的数据,也就是1440 ((5d x 24h x 12m = 1440) 条记录。所以在Oracle9iR2中,表属性修改时间和flashback时间差至少应为5分钟。否则就会出现ORA-01466错误


SQL> select thread,time_mp,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss'),scn_wrp,scn_bas from smon_scn_time ;


    THREAD    TIME_MP TO_CHAR(TIME_DP,'YY    SCN_WRP    SCN_BAS

---------- ---------- ------------------- ---------- ----------

         1 1463195362 2016-05-14 11:09:24          0     252950

         1 1463195670 2016-05-14 11:14:31          0     254047

         1 1463196445 2016-05-14 11:27:25          0     274757

         1 1463196752 2016-05-14 11:32:33          0     276521

         1 1463197061 2016-05-14 11:37:41          0     277760

         1 1463197368 2016-05-14 11:42:49          0     278504

         1 1463197672 2016-05-14 11:47:56          0     279318

         1 1463197983 2016-05-14 11:53:03          0     280126


已选择107行。


2truncate后重新测试

SQL> truncate table zhong;

表已截掉。


SQL> execute dbms_flashback.enable_at_system_change_number(275829);

PL/SQL 过程已成功完成。


SQL> select count(*) from zhong;

select count(*) from zhong

                     *

ERROR 位于第 1 行:

ORA-01466: 无法读数据 - 表定义已更改


SQL> execute dbms_flashback.disable;

PL/SQL 过程已成功完成。



-------------------------------------------------------

3)环境准备

SQL> begin

  2  for i in 1..99999 loop

  3  insert into zhong values(i,'shall');

  4  end loop;

  5  commit;

  6  end;

  7  /

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

     99999

 

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

TO_CHAR(SYSDATE,'YY

-------------------

2016-05-14 12:03:44

 

SQL> select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

                  282784

SQL>

SQL> select thread,time_mp,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss'),scn_wrp,scn_bas from smon_scn_time ;

 

         1 1463197983 2016-05-14 11:53:03          0     280126

         1 1463198288 2016-05-14 11:58:10          0     281285

         1 1463198596 2016-05-14 12:03:18          0     282698

 

4)等待scn记录......

SQL> select thread,time_mp,to_char(time_dp,'yyyy-mm-dd hh24:mi:ss'),scn_wrp,scn_bas from smon_scn_time ;

      1 1463197983 2016-05-14 11:53:03          0     280126

      1 1463198288 2016-05-14 11:58:10          0     281285

      1 1463198596 2016-05-14 12:03:18          0     282698

      1 1463198903 2016-05-14 12:08:25          0     283509

5)删除数据

SQL> delete zhong;

已删除99999行。

SQL> commit;

提交完成。

 

6)闪回查询数据

SQL> execute dbms_flashback.enable_at_time(to_date('2016-05-14 12:03:44','yyyy-mm-dd hh24:mi:ss'));

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

     99999

 

SQL> execute dbms_flashback.disable;

PL/SQL 过程已成功完成。

 

4利用闪回恢复数据(9i

1)利用闪回时间恢复数据

declare

  cursor zhong_recover is select * from zhong;

  t_recode zhong%rowtype;

begin

  dbms_flashback.enable_at_time(to_date('2016-05-14 12:03:44','yyyy-mm-dd hh24:mi:ss'));

   open zhong_recover;

  dbms_flashback.disable;

  loop fetch zhong_recover into t_recode;exit when zhong_recover%notfound;

    insert into zhong values(t_recode.id,t_recode.name);

  end loop;

  close zhong_recover;

  commit;

end;

/

PL/SQL 过程已成功完成。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

     99999

2)利用闪回scn恢复数据

先删除之前恢复的部分数据

SQL> delete zhong where id>400;

已删除99599行。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

       400

SQL> commit;

提交完成。

 

创建表recover用于存放恢复数据

SQL> create table recover as select * from zhong where 1=0;

表已创建。

 

SQL> select * from recover;

未选定行

 

开始闪回恢复

declare

  cursor zhong_recover is select * from zhong;

  t_recode zhong%rowtype;

begin

  dbms_flashback.enable_at_system_change_number(282784);

   open zhong_recover;

  dbms_flashback.disable;

  loop fetch zhong_recover into t_recode;exit when zhong_recover%

notfound;

    insert into zhong values(t_recode.id,t_recode.name);

    insert into recover values(t_recode.id,t_recode.name);

  end loop;

  close zhong_recover;

  commit;

end;

/

PL/SQL 过程已成功完成。

 

SQL> select count(*) from recover;

  COUNT(*)

----------

     99999

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

    100399

3)当恢复的数据再次写入到原表中时,会出现重复的数据,下面进行去重

--------------去重

delete from zhong

  where id in (select id from zhong

                    group by id

                    having count(id)>1)

  and rowid not in(select max(rowid) from zhong

                      group by id

                      having count(id)>1);

已删除400行。

 

SQL> select count(*) from zhong;

  COUNT(*)

----------

     99999

 

SQL> commit;

提交完成。

 

去重也这样写:

delete zhong z1

         where z1.rowid <> (select max(rowid) from zhong z2

                                                        where z1.id=z2.id);

 

5.oracle 10g后flashback query新特性恢复数据实验

1)环境准备

----数据库的模式

sys@ORCL>select log_mode,flashback_on,open_mode from v$database;

 

LOG_MODE     FLASHBACK_ON       OPEN_MODE

------------ ------------------ --------------------

NOARCHIVELOG  NO                 READ WRITE

 

----创建测试表

sys@ORCL>create table shall as select * from dba_objects;

Table created.

sys@ORCL>select count(*) from shall;

  COUNT(*)

----------

     86565

 

2)记录当前时间

sys@ORCL>select to_char(sysdate,'yyyy-mm-dd hh24:mi:ss') from dual;

TO_CHAR(SYSDATE,'YY

-------------------

2016-05-02 05:40:08

 

sys@ORCL>select dbms_flashback.get_system_change_number from dual;

GET_SYSTEM_CHANGE_NUMBER

------------------------

                 2687027

 

3)删除数据并提交

sys@ORCL>delete shall;

86565 rows deleted.

 

sys@ORCL>commit;

Commit complete.

 

4)闪回查询

sys@ORCL>select count(*) from shall;

  COUNT(*)

----------

         0

 

sys@ORCL>select count(*) from shall as of timestamp to_timestamp('2016-05-02 05:40:08','yyyy-mm-dd hh24:mi:ss');

  COUNT(*)

----------

     86565

 

sys@ORCL>select count(*) from shall as of scn 2687027;

  COUNT(*)

----------

     86565

 

5)闪回恢复数据

sys@ORCL>insert into shall select * from shall as of scn 2687027;

86565 rows created.

 

sys@ORCL>select count(*) from shall;

  COUNT(*)

----------

     86565

 

sys@ORCL>commit;

Commit complete.

 

------如果删除数据后,表做了move或者说truncate表后还能恢复吗?No!

sys@ORCL>select sysdate from dual;

SYSDATE

-------------------

2016-05-02 05:48:02

 

sys@ORCL>delete shall;

86565 rows deleted.

 

sys@ORCL>alter table shall move;

Table altered.

 

sys@ORCL>select count(*) from shall as of timestamp to_timestamp('2016-05-02 05:48:02','yyyy-mm-dd hh24:mi:ss');

select count(*) from shall as of timestamp to_timestamp('2016-05-02 05:48:02','yyyy-mm-dd hh24:mi:ss')

                     *

ERROR at line 1:

ORA-01466: unable to read data - table definition has changed

 

 

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/30130773/viewspace-2102639/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/30130773/viewspace-2102639/

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值