[原]记一次使用flashback恢复数据,警惕自己不要浮躁,还是太嫩了
周五晚十点多,同事突然来电称操作CMS后台的时候不小心删除了很多记录(其实应该是这个CMS的逻辑问题),大概了解了情况以后,能初步判断为p_web表的2万多条数据被delete了,事发时间大概在9:30左右,这种场景几乎就是“专门”为flashback而设的了。
于是马上翻开书找到flashback那节书,先鄙视一下自己,以前所学的都还给书本了。
确认一下可以flashback的极限是多少
select min(start_timestamp) from flashback_transaction_query where table_name='P_WEB' and table_owner='CMS'
结果是前天的下午3点,比预期中的时间要长很多啊。
由于p_web表数据量不大,还不到100M,赶紧做个“备份”,免得突然犯浑把剩下的2万多条记录都整丢了,那就可以跳楼了:
create table p_web_bad as select * from p_web;
使用flashback query将9:20的数据放在一个p_web_20100507_0920表里面,让同事看看效果先:
create table p_web_20100507_0920 as select * from p_web as of timestamp to_date('2010-05-07 21:20:00','yyyy-mm-dd hh24:mi:ss');
其实我也是笨,脱离了表现层的数据能看出什么呢?除了“感觉”上是正确的一点说服力也没有。
同事说这个数据没问题。为了进一步确定事发的准确时间点,使用flashback transaction query 将自8:30以来的所有undo操作列出,这样可以找出什么时候开始删除的了。
create table p_web_undo_20100507_2030 as select start_timestamp,operation,undo_sql from flashback_transaction_query where table_name='P_WEB' and table_owner='CMS' and start_timestamp>to_date('2010-05-07 20:30:00','yyyy-mm-dd hh24:mi:ss') order by start_timestamp desc
经过一个简单的查询从start_timestamp 能查出是21:39:04开始删除的,只要将flashback到21:38:00问题就OK了啦。
flashback table p_web to timestamp to_date('2010-05-07 21:38:00','yyyy-mm-dd hh24:mi:ss');
此时,报了一个错:
ORA-08189: cannot flashback the table because row movement is not enabled
小问题,enable row movement 就是了
alter table p_web enable row movement;
我再闪(flashback):
flashback table p_web to timestamp to_date('2010-05-07 21:38:00','yyyy-mm-dd hh24:mi:ss');
shit!竟然出现了flashback的克星:
ora-01555 snapshot too old
明明前面查到可以flashback的时间很长的啊,莫非是前面几个大create table把undo内容刷走了,这也太快了吧@_@!
先不管了,我同事还在着急的等待,虽然没有催我,但是“弄丢”数据的心情我很清楚。
幸好前面创建了一个p_web_undo_20100507_2030表,里面有一对undo的sql,可以将被delete的数据再insert回去。
于是写了个简单的过程做这件事:
declare v_undo_sql varchar2(4000); CURSOR cur is select substr(undo_sql,1,length(undo_sql)-1) --将undo_sql最后那个分号去掉 from p_web_undo_20100507_2030 where operation='DELETE'; BEGIN open cur; loop fetch cur into v_undo_sql; EXIT when cur%NOTFOUND; execute immediate v_undo_sql; --dbms_output.put_line(v_undo_sql); END LOOP; CLOSE cur; END delete_state ;
经过“漫长”的等待,终于将误删的数据恢复回来了。
经过这次数据恢复让我认识到:
1。虽然掌握了基本概念,但是熟练程度还不够,体现在临急翻书上。
2。实际操作经验欠缺,整个过程实际上没多少东西,但是却足足折腾了一个半小时。
3。前瞻性不足,这个数据库是我维护的,对于误操作删除数据这种问题应该要有所觉悟,就这个问题而言,我做的措施仅仅是扩大了undo表空间。
总的来说,就是太嫩了。