ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 老贾笔记--轻轻松松oracle之logmnr篇[吃顿饭的功夫学恢复误删除(delete)的数据]

老贾笔记--轻轻松松oracle之logmnr篇[吃顿饭的功夫学恢复误删除(delete)的数据]

原创 Linux操作系统 作者:jcq0 时间:2009-01-12 16:16:17 0 删除 编辑

老贾曰:把大象放到冰箱里分几步?
      答:分三步,把冰箱门打开,把大象放进去,把冰箱门关上
老贾曰:聪明,那吃一顿饭分几步?
      答:俺不晓得
老贾曰:不晓得就让俺来告诉你吧

0.吃饭环境

吃饭当然要先选择一个好的环境,让谁在厕所里吃估计谁也吃不下
如果你一定能的话,老贾去陪你一起吃

jcq0>select * from v$version;

BANNER
----------------------------------------------------------------
Oracle9i Enterprise Edition Release 9.2.0.1.0 - Production
PL/SQL Release 9.2.0.1.0 - Production
CORE    9.2.0.1.0       Production
TNS for 32-bit Windows: Version 9.2.0.1.0 - Production
NLSRTL Version 9.2.0.1.0 - Production

1.饭前准备

不想吃的别准备
想吃不准备的让你吃也吃不下

不过,老贾提醒你一下,其实这两步准备也不一定是必须的,具体就看下面的要求吧

1.1参数utl_file_dir已配置(如果生成日志文件的库和当前数据库为同一个库,本步可略过)

等...等一下
为啥生成日志文件的库和当前数据库为同一个库可略过这一步
这个嘛,不要着急,听老贾在最后的章节慢慢道来

针对生成日志文件的库和当前数据库不为同一个库的情况
要把后面的数据字典生成在这个位置
这个参数不配虽然不会死人,但是在使用logmnr挖掘的第一步就会报错

jcq0> show parameter utl_file_dir

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
utl_file_dir                         string      e:\
否则在后面执行要报错
jcq0> begin
  2    dbms_logmnr_d.build(
  3      dictionary_filename => 'jcq0.dict',
  4      dictionary_location => 'e:\'
  5   );
  6   end;
  7  /
begin
*
ERROR 位于第 1 行:
ORA-01308: 未设置初始化参数 utl_file_dir
ORA-06512: 在"SYS.DBMS_LOGMNR_D", line 923
ORA-06512: 在"SYS.DBMS_LOGMNR_D", line 1938
ORA-06512: 在line 2

1.2归档模式
当然,如果你分析重做日志就不需要了
如果你是生产库,那还是分析归档日志吧

jcq0> archive log list
数据库日志模式            存档模式
自动存档             启用
存档终点            D:\oracle\oradata\db_namex\archive
最早的概要日志序列     16
下一个存档日志序列   18
当前日志序列           18

2.做做饭
没有环境制造环境也要上
下面就模拟一个delete操作

2.1 为了缩小分析范围,先做一次日志切换

jcq0> alter system switch logfile;

系统已更改。

jcq0> delete  from b.big_table where id=10000 or id=9999;

已删除2行。

jcq0> commit;

提交完成。

2.2这样所有的redo undo信息都定位在下面的归档日志中了

jcq0> alter system switch logfile;

系统已更改。

刚才的delete操作就记录在切过之后的归档日志中了

D:\oracle\oradata\db_namex\archive>dir /t
 驱动器 D 中的卷是 PROC
 卷的序列号是 243B-0BC1

 D:\oracle\oradata\db_namex\archive 的目录

2009-01-08  13:01   

          .
2009-01-08  13:01              ..
......
2009-01-08  13:01             3,072 ARC00019.001
              20 个文件    155,865,600 字节
               3 个目录    407,769,088 可用字节

一坨美味热气腾腾的归档日志ARC00019.001就这么出炉了

3.开始吃饭

要吃就要先选择吃饭的位置
看见那坨热气腾腾香喷喷的东东你是想在厨房里就把它解决掉呢
还是想拿到餐厅找个蹲位蹲下慢条斯柳的享受呢,如果想在餐厅吃,千万别忘了把饭端过去哦
空着手过去你吃个屁啊

同样,生成的这个归档日志你是想放在本地(生成这个文件的库)处理呢
还是想放在别的数据库上处理呢
如果你迫不及待的想把美味解决掉,那可以省去一些功夫,3.1步就不需要了

3.1生成数据字典

如果生成日志文件的库和当前数据库为同一个库


jcq0> begin
  2    dbms_logmnr_d.build(
  3      dictionary_filename => 'jcq0.dict',
  4      dictionary_location => 'e:\'
  5   );
  6   end;
  7  /

PL/SQL 过程已成功完成。

如果没有数据字典也是可以分析的只不过分析出的语句类似下面的
jcq0>SELECT operation,sql_redo FROM V$logmnr_contents where rownum<=2;

OPERATION
--------------------------------
SQL_REDO
--------------------------------------------------------------------------------

DELETE
delete from "UNKNOWN"."OBJ# 26920" where "COL 1" = HEXTORAW('c26464') and "COL 2

" = HEXTORAW('5055424c4943') and "COL 3" = HEXTORAW('2f313131366265365f526f756e6

452656374616e676c653244466c6f6174') and "COL 4" IS NULL and "COL 5" = HEXTORAW('

c3021742') and "COL 6" IS NULL and "COL 7" = HEXTORAW('53594e4f4e594d') and "COL

 8" = HEXTORAW('786c070814021e') and "COL 9" = HEXTORAW('786c070814021e') and "C

OL 10" = HEXTORAW('323030382d30372d30383a31393a30313a3239') and "COL 11" = HEXTO

RAW('56414c4944') and "COL 12" = HEXTORAW('4e') and "COL 13" = HEXTORAW('4e') an

d "COL 14" = HEXTORAW('4e') and ROWID = 'AAAGkrAADAAAAEaAAk';

咋样?没有字典翻译你看不懂吧,呵呵

这步就是建立类似对象号和对象名的对应关系
没有这步你最终得到的语句就会象上面的那样
这里的jcq0.dict就是一个字典,输入对象号,可以返回对象名

想在厨房就地吃掉的朋友应该清楚些了吧,
本地的数据库已经存在了@#$@这些符号与对象名啊,列名啊之类的对应关系
所以就不用生成数据字典了

3.2添加重做日志或归档日志

你是想分析一个归档日志(或者重做日志)还是n个呢
统统加进来吧

jcq0> begin
  2      dbms_logmnr.add_logfile(
  3      ptions => dbms_logmnr.NEW,
  4      logfilename => 'D:\oracle\oradata\db_namex\archive\ARC00019.001'
  5      );
  6  end;
  7  /

PL/SQL 过程已成功完成。

除了可以往里加还可以往外删哦,真是神奇

jcq0>begin
  2  dbms_logmnr.add_logfile(
  3  LogFileName => 'D:\oracle\oradata\db_namex\archive\ARC00019.001',
  4  ptions => dbms_logmnr.REMOVEFILE);
  5  end;
  6  /

3.3开始分析

3.3.1 做饭和吃饭在一个地方滴

咱本地就有数据字典,所以省了生成数据字典的麻烦,只要指定对应得参数就可以了

jcq0> begin
  2      dbms_logmnr.start_logmnr(
  3                 ptions =>dbms_logmnr.dict_from_online_catalog
  4      );
  5  end;
  6  /

PL/SQL 过程已成功完成。

3.3.2做饭和吃饭不在一个地方滴

分析的时候要随身带上你的字典(jcq0.dict)哦
他会把你看不明白的东西翻译成可读的
光着屁股的sql语句是看不懂滴

jcq0> begin
  2      dbms_logmnr.start_logmnr(
  3                  DictFileName => 'e:\jcq0.dict'
  4      );
  5  end;
  6  /

PL/SQL 过程已成功完成。

3.4捕获语句

所有在归档日志期间进行的操作都记录在 v$logmnr_contents里了
尽情的查吧,想查啥就查啥
不想查你就一边凉快78

jcq0> SELECT operation,
  2              sql_redo,sql_undo
  3        FROM v$logmnr_contents
  4       WHERE seg_name ='BIG_TABLE';

OPERATION
--------------------------------
SQL_REDO
--------------------------------------------------------------------------------

SQL_UNDO
--------------------------------------------------------------------------------

DELETE
delete from "B"."BIG_TABLE" where "ID" = '9999' and "OWNER" = 'PUBLIC' and "OBJE

CT_NAME" = '/1116be6_RoundRectangle2DFloat' and "SUBOBJECT_NAME" IS NULL and "OB

JECT_ID" = '12265' and "DATA_OBJECT_ID" IS NULL and "OBJECT_TYPE" = 'SYNONYM' an

d "CREATED" = TO_DATE('08-7月 -08', 'DD-MON-RR') and "LAST_DDL_TIME" = TO_DATE('

08-7月 -08', 'DD-MON-RR') and "TIMESTAMP" = '2008-07-08:19:01:29' and "STATUS" =

 'VALID' and "TEMPORARY" = 'N' and "GENERATED" = 'N' and "SECONDARY" = 'N' and R


OPERATION
--------------------------------
SQL_REDO
--------------------------------------------------------------------------------

SQL_UNDO
--------------------------------------------------------------------------------

OWID = 'AAAGkrAADAAAAEaAAk';
insert into "B"."BIG_TABLE"("ID","OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_

ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAMP","STATUS

","TEMPORARY","GENERATED","SECONDARY") values ('9999','PUBLIC','/1116be6_RoundRe

ctangle2DFloat',NULL,'12265',NULL,'SYNONYM',TO_DATE('08-7月 -08', 'DD-MON-RR'),T

O_DATE('08-7月 -08', 'DD-MON-RR'),'2008-07-08:19:01:29','VALID','N','N','N');


OPERATION
--------------------------------
SQL_REDO
--------------------------------------------------------------------------------

SQL_UNDO
--------------------------------------------------------------------------------

DELETE
delete from "B"."BIG_TABLE" where "ID" = '10000' and "OWNER" = 'PUBLIC' and "OBJ

ECT_NAME" = '/1117a35c_MutationEvent' and "SUBOBJECT_NAME" IS NULL and "OBJECT_I

D" = '22936' and "DATA_OBJECT_ID" IS NULL and "OBJECT_TYPE" = 'SYNONYM' and "CRE

ATED" = TO_DATE('08-7月 -08', 'DD-MON-RR') and "LAST_DDL_TIME" = TO_DATE('08-7月

 -08', 'DD-MON-RR') and "TIMESTAMP" = '2008-07-08:19:03:42' and "STATUS" = 'VALI

D' and "TEMPORARY" = 'N' and "GENERATED" = 'N' and "SECONDARY" = 'N' and ROWID =


OPERATION
--------------------------------
SQL_REDO
--------------------------------------------------------------------------------

SQL_UNDO
--------------------------------------------------------------------------------

 'AAAGkrAADAAAAEaAAl';
insert into "B"."BIG_TABLE"("ID","OWNER","OBJECT_NAME","SUBOBJECT_NAME","OBJECT_

ID","DATA_OBJECT_ID","OBJECT_TYPE","CREATED","LAST_DDL_TIME","TIMESTAMP","STATUS

","TEMPORARY","GENERATED","SECONDARY") values ('10000','PUBLIC','/1117a35c_Mutat

ionEvent',NULL,'22936',NULL,'SYNONYM',TO_DATE('08-7月 -08', 'DD-MON-RR'),TO_DATE

('08-7月 -08', 'DD-MON-RR'),'2008-07-08:19:03:42','VALID','N','N','N');

刚才做的delete操作尽收眼底了吧
想要恢复原样就看看SQL_UNDO字段吧

这么精彩的内容只属于你一个人哦,换了session你是看不见滴
SQL> select * from  v$logmnr_contents;
select * from  v$logmnr_contents
               *
ERROR 位于第 1 行:
ORA-01306: 在从 v$logmnr_contents 中选择之前必须调用 dbms_logmnr.start_logmnr()

4.吃完收工

吃完饭怎么能不擦屁股呢
把该清理的都清理了

jcq0> begin
  2      dbms_logmnr.end_logmnr;
  3  end;
  4  /

PL/SQL 过程已成功完成。

清理完毕再看看
jcq0>select * from v$logmnr_contents;
select * from v$logmnr_contents
              *
ERROR 位于第 1 行:
ORA-01306: 在从 v$logmnr_contents 中选择之前必须调用 dbms_logmnr.start_logmnr()

v$logmnr_contents顿时化为灰烬

5.消化消化

老贾提醒你很多东西还是需要好好消化才能吸收滴
你要吃了馒头 又拉出来一个馒头 那还吃它干啥呢
如果你能吃了馒头 拉出小麦了 那你就更牛了

由于delete是dml操作,所以会生成相应得redo和undo信息,所以我们通过分析重做日志或归档日志找到相应得重做语句.

如果是drop或truncate,可能就稍微麻烦一些了,因为他们是ddl操作,不可回退,也没有行级别的重做信息,只能通过备份做基于时间点的不完全恢复再取回这张表.

在9i版本中,oracle提供了flashback query特性实现了类似功能,但是会受到NLS_DATE_FORMAT设置,表结构更改,undo_retention,scn与时间映射信息更新时间(5分钟),scn与时间对应信息保留时间(5天)的限制.

在10g版本中,oracle对flashback特性做了很大的增强,可以分别完成flashback database,flashback drop,flashback table,flash back versions query,flashback transaction query,当然这些特性也是以牺牲空间为代价的.

老贾曰:这回明白了吧
      答:嗯,原来吃饭也是要分步骤的,可是消化完了干啥呢?
老贾曰:消化完就完了啊,你还想咋
      答:我不想怎么样啊,就是觉得小腹有坠胀的感觉
老贾曰:那你该干啥干啥78

(需要引用, 请注明出处:痴情甲骨文http://space.itpub.net/14130873)

 

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

请登录后发表评论 登录
全部评论

注册时间:2008-11-25

  • 博文量
    93
  • 访问量
    347075