How to locate SCN/Time of DROP TABLE using LogMiner [ID 93370.1]

How to locate SCN/Time of DROP TABLE using LogMiner [ID 93370.1]

 Modified 17-APR-2009     Type BULLETIN     Status PUBLISHED 
PURPOSE
  This article discusses and demonstrates how to locate and analyze a DROP 
  TABLE statement in online and archived redo logs using LogMiner.  This 
  article is not intended to present LogMiner basics - refer to the Oracle8i 
  Administrator's Guide and Supplied Packages Reference for LogMiner 
  introduction and general instructions. 

  The procedure outlined in this article results in information (SCN/Time) to 
  assist Point-in-Time Recovery (PITR) for an unintentional dropped table. 
  Refer to Note:96197.1 for a step-by-step procedure to recover a dropped 
  table from a full database backup.
  
SCOPE & APPLICATION

 This article assumes the reader has basic understanding of fixed tables 
 and LogMiner.  

RELATED DOCUMENTS

 Note:74988.1 How to build an Oracle 8.0 LogMiner Dictionary
 Note:96197.1 Recovering a Dropped Table from a Full Database Backup

 Oracle 8.1.5 Administrator's Guide - Managing Archived Redo Logs Chapter
 Oracle 8.1.5 Supplied Packages Reference: dbms_logmnr_d, dbms_logmnr


How to locate SCN/Time of DROP TABLE using LogMiner:
====================================================

LogMiner Overview

LogMiner (packages dbms_logmnr_d and dbms_logmnr) provides a SQL interface to 
review information contained in Oracle8 online and archived redo logs.  The 
LogMiner dictionary allows queries against v$logmnr_contents to be easily 
understood. This dictionary provides schema, object, column and datatype 
translations. Note: v$logmnr_contents.seg_name is only populated if a LogMiner 
dictionary is used!

Example 1 :  LogMiner analysis using a dictionary file.

SQL> select sql_redo from v$logmnr_contents;
SQL_REDO
--------------------------------------------------------------------------------
set transaction read write;
insert into TEST.TAB1(C1) values (1);
commit;

Example 2: LogMiner analysis without a dictionary file.

SQL> select sql_redo from v$logmnr_contents;
SQL_REDO
--------------------------------------------------------------------------------
set transaction read write;
insert into UNKNOWN.Objn:13079(Col[1]) values (HEXTORAW('c102'));
commit;

Only Data Manipulation Language (DML) and transaction control generates 
redo/undo that is translated by LogMiner.  Data Definition Language (DDL), such
as DROP TABLE, actually performs DML on dictionary objects (i.e. SYS.TAB$, 
SYS.OBJ$), but DML on most dictionary objects do not have translations in 
Oracle 8.1.5, therefore analysis may require hex conversion.  Note: SYS.OBJ$ is
translated if a LogMiner dictionary is specified in dbms_logmnr.start_logmnr 
but SYS.TAB$ is not translated regardless of dictionary specification.

Although the LogMiner dictionary file assists in locating a DDL for a specfic 
object - the actual dictionary file will also be used since SELECTs are not 
allowed against the temporary objects built when the dictionary is loaded 
(dbms_logmnr.logmnr_start).  As an alternative method, it is possible to 
convert the dictionary file into a SQL script which will build normal database 
objects.  Refer to the comments in the header of the dictionary file created by
dbms_logmnr_d.build for instructions.  This procedure will not be demonstrated 
in this article.

Assumptions:  

It is assumed that a dictionary file exists from a time when the dropped table 
existed. A dictionary file MUST be specified in dbms_logmnr.start_logmnr in 
order to populate v$logmnr_contents.seg_name.  If a dictionary file is not 
specified v$logmnr_contents.seg_name will be NULL for every redo/undo entry.  
The SCN/Time of a DROP TABLE can be determined even if a LogMiner dictionary 
does not contain the dropped table.

It is also assumed that the exact on-line and/or archived redo log file 
spanning the time of the DROP table is known.  The larger the DROP time 
estimate - the more redo log files will require analysis.  Either 1) multiple 
redo log files can be loaded into LogMiner (dbms_logmnr.add_logfile) for a 
single LogMiner analysis session or 2) a LogMiner analysis session can be run
individually for each redo log file - starting with the 'best guess'.
  

*** Locating DROP TABLE Overview:

1.  Locate on-line and/or archived redo logs for time corresponding with 
    DROP TABLE.
2.  If possible, locate the dictionary file that was created while table 
    existed, otherwise generate a LogMiner dictionary file for the database.
3.  Load the redo logs into LogMiner (dbms_logmnr.add_logfile)
4.  Load dictionary objects supporting LogMiner (dbms_logmnr.start_logmnr)
5.  Process redo logs and extract information (v$logmnr_contents).
5a. (*) CREATE TABLE AS SELECT (CTAS) to move the rows of v$logmnr_contents 
    into a temporary table.  Since each SELECT of v$logmnr_contents performs 
    physical file read of the loaded redo logs - this step can be omitted if 
    the redo log is small, but is a time savings if processing a lot of redo.
    A temporary table will also facilitate analysis beyond a single session.
6.  Locate the DROP TABLE by locating associated DML on fixed tables.

(*) Optional

Locating DROP TABLE Example:

For ease of discussion, SQL statements are intentionally isolated into very
small redo log files using ALTER SYSTEM SWITCH LOGFILE.  Without question - 
this is not a 'real-world' example for redo log files are typically quite large
for performance reasons.

*** ---------------------------------------------------------------------------
*** Setup: Create table and build LogMiner dictionary.
*** ---------------------------------------------------------------------------

SQL> create table tab1 (
  2  c1 integer,
  3  c2 integer,
  4  c3 integer);

Table created.

SQL> connect internal
Connected.

SQL> select value from v$parameter where name = 'utl_file_dir';

VALUE
--------------------------------------------------------------------------------
/database/V815/extproc

SQL> begin
  2  sys.dbms_logmnr_d.build(dictionary_filename => 'dictionary.ora',
  3                          dictionary_location => '/database/V815/extproc');
  4  end;
  5  /

PL/SQL procedure successfully completed.


*** ---------------------------------------------------------------------------
*** Setup: Isolate DROP TABLE into an archive log
*** ---------------------------------------------------------------------------

SQL> alter system switch logfile;

System altered.

SQL> select sequence# from v$log where status = 'CURRENT';

 SEQUENCE#
----------
        22

SQL> drop table tab1;

Table dropped.

SQL> alter system switch logfile;

System altered.


*** ---------------------------------------------------------------------------
*** Analysis
*** ---------------------------------------------------------------------------

SQL> -- Load archive log into LogMiner.
SQL> begin
  2  dbms_logmnr.add_logfile (
  3  LogFileName =>
  4     '/database/V815/archivelogs/V815_ArchiveLog_1_0000000022.dbf',
  5  Options => dbms_logmnr.new);
  6  end;
  7  /

PL/SQL procedure successfully completed.

SQL> -- Prepare LogMiner for analysis.
SQL> begin
  2  dbms_logmnr.start_logmnr (
  3  dictFileName => '/database/V815/extproc/dictionary.ora');
  4  end;
  5  /

PL/SQL procedure successfully completed.

SQL> -- DROP TABLE will generate DML on fixed tables
SQL> -- Notes:
SQL> -- 1.  The goal is to locate a single transaction (SCN) the performs a
SQL> --     DELETE operation on SYS.COL$ (columns), SYS.OBJ$ (objects) and
SQL> --     SYS.TAB$ (tables) for this identifies a DROP TABLE statement.
SQL> -- 2.  There will be one DELETE operation on SYS.COL$ for each column.
SQL> -- 3.  DML on SYS.SEG$ (segments), SYS.UET$ (used space), SYS.FET$ (free
SQL> --     space) and SYS.TSQ$ (tablespace quotas) perform segment and space
SQL> --     cleanup.  DML on these fixed tables do not necessarily indicate
SQL> --     DROP TABLE.
SQL> -- 4.  Refer to $ORACLE_HOME/rdbms/admin/sql.bsq for additional information
SQL> --     regarding fixed tables.

SQL> -- Summarize contents of archive log. Not advised for large redo files.
SQL> -- v$logmnr_contents.operation = 'INTERNAL' implies sql_redo is NULL.
SQL> -- A LogMiner dictionary must be specified for v$logmnr_contents.seg_name
SQL> -- population - which is essential for this procedure.

SQL> column seg_name format a15 trunc
SQL> select seg_name, operation, scn, count(*) from v$logmnr_contents
  2  where operation != 'INTERNAL'
  3  group by seg_name, operation, scn
  4  order by scn;

SEG_NAME        OPERATION                               SCN   COUNT(*)
--------------- -------------------------------- ---------- ----------
                COMMIT                              5012064          1
COL$            DELETE                              5012065          3
OBJ$            DELETE                              5012065          1
TAB$            DELETE                              5012065          1
                START                               5012065          1
SEG$            UPDATE                              5012065          1
                COMMIT                              5012066          1
SEG$            DELETE                              5012067          1
UET$            DELETE                              5012067          1
FET$            INSERT                              5012067          1
                START                               5012067          1
TSQ$            UPDATE                              5012067          1
                COMMIT                              5012068          1

13 rows selected.

SQL> -- DROP TABLE will generate DELETE operations on COL$, OBJ$ and TAB$
SQL> -- Since SELECT on v$logmnr_contents physically reads the redo files,
SQL> -- CREATE TABLE AS SELECT (CTAS) can be used to move associated data from
SQL> -- v$logmnr_contents into a temporary table.  The temporary table may
SQL> -- contain DML associated with DML other than DROP TABLE including DROP
SQL> -- COLUMN, DROP INDEX, etc. Moving the relevant contents of 
SQL> -- v$logmnr_contents into a temporary table will also facilitate 
SQL> -- analysis spanning sessions.

SQL> create table temp
  2  as select * from v$logmnr_contents
  3  where operation = 'DELETE'
  4  and seg_name in ('COL$','OBJ$','TAB$');

Table created.

SQL> -- The remainder of the example will reference TEMP but all SQL could
SQL> -- be modified to use v$logmnr_contents.

SQL> -- Verify that DROP TABLE exists in analyzed redo files.  If there does not
SQL> -- exist a single SCN that performs a DELETE operation on COL$, OBJ$ and
SQL> -- TAB$ then more redo files must be loaded into LogMiner for analysis.
SQL> -- At some point, the time spent performing redo analysis must be weighted
SQL> -- against the total time to object recovery, for processing redo with
SQL> -- LogMiner can be a time consuming task.

SQL> select seg_name, operation, scn, count(*) from temp
  2  where operation != 'INTERNAL'
  3  group by seg_name, operation, scn
  4  order by scn;

SEG_NAME        OPERATION                               SCN   COUNT(*)
--------------- -------------------------------- ---------- ----------
COL$            DELETE                              5012065          3
OBJ$            DELETE                              5012065          1
TAB$            DELETE                              5012065          1

SQL> -- Locate SCNs of all DROP TABLE statement(s).
SQL> -- This is only necessary if the resulting rows from the previous query
SQL> -- is to large to easily inspect.  Clearly this is not necessary 
SQL> -- for this example, for the redo file only contains DML associated with
SQL> -- a single DROP TABLE statement.

SQL> select scn from v$logmnr_contents
  2  where operation = 'DELETE' and seg_name = 'COL$'
  3  intersect
  4  select scn from v$logmnr_contents
  5  where operation = 'DELETE' and seg_name = 'OBJ$'
  6  intersect
  7  select scn from v$logmnr_contents
  8  where operation = 'DELETE' and seg_name = 'TAB$';

       SCN
----------
   5012065

SQL> -- At this point we have collected a list of SCN(s) associated with DROP
SQL> -- TABLE. Using LogMiner dictionary if available, analyze sql_redo to
SQL> -- determine dropped tables.  

SQL> select sql_redo from temp
  2  where scn = 5012065 and seg_name = 'TAB$';

SQL_REDO
--------------------------------------------------------------------------------
delete from UNKNOWN.Objn:4 where Col[1] = HEXTORAW('c3021f50') and Col[2] = HEXT
ORAW('c102') and Col[3] = HEXTORAW('c103') and Col[4] = HEXTORAW('c2034e') and C
ol[5] IS NULL and Col[6] IS NULL and Col[7] = HEXTORAW('c104') and Col[8] IS NUL
L and Col[9] = HEXTORAW('c10b') and Col[10] = HEXTORAW('c129') and Col[11] = HEX
TORAW('c102') and Col[12] = HEXTORAW('c20338') and Col[13] = HEXTORAW('c102') an
d Col[14] = HEXTORAW('2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d
2d2d2d') and Col[15] IS NULL and Col[16] IS NULL and Col[17] IS NULL and Col[18]
 IS NULL and Col[19] IS NULL and Col[20] IS NULL and Col[21] IS NULL and Col[22]
 IS NULL and Col[23] IS NULL and Col[24] IS NULL and Col[25] IS NULL and Col[26]
 IS NULL and Col[27] = HEXTORAW('c104') and Col[28] = HEXTORAW('c104') and Col[2
9] = HEXTORAW('80') and Col[30] = HEXTORAW('80') and Col[31] = HEXTORAW('c20441'
) and Col[32] IS NULL and Col[33] = HEXTORAW('80') and ROWID = 'AAAAACAABAAAH1ZA
AA';

SQL> -- Col[1] corresponds to tab$.obj#
SQL> -- Hex to raw conversion of data results in object id (Oracle internal value)
SQL> -- Using LogMiner dictionary, locate INSERT_INTO OBJ$_TABLE for the
SQL> -- object id deleted from TAB$.  The 4th column in OBJ$ is the object name.

SQL> select distinct timestamp from temp where scn = 5012065;

TIMESTAMP
--------------------
2000-JAN-18 12:36:23

NOTE:  This timestamp is for scn 5012065, when the drop table statement was 
       submitted.

Extract from /database/V815/extproc/dictionary.ora:

INSERT_INTO OBJ$_TABLE VALUES (13079,13079,38,'TAB1',1,'',2,to_date('01/18/2000
12:25:28', 'MM/DD/YYYY HH24:MI:SS'),to_date('01/18/2000 12:25:28', 'MM/DD/YYYY H
H24:MI:SS'),to_date('01/18/2000 12:25:28', 'MM/DD/YYYY HH24:MI:SS'),1,'','',0,,,
,,'','', );


SQL> -- Note that the same information can be found from the SQL redo of the
SQL> -- DELETE operation on OBJ$ for the SCN without using the dictionary:
SQL> -- OBJ$.OBJ# = 13709, OBJ$.NAME = 'TAB1'.

SQL> select sql_redo from temp
  2  where scn = 5012065 and seg_name = 'OBJ$';

SQL_REDO
--------------------------------------------------------------------------------
delete from SYS.OBJ$ where OBJ# = 13079 and DATAOBJ# = 13079 and OWNER# = 38 and
 NAME = 'TAB1' and NAMESPACE = 1 and SUBNAME IS NULL and TYPE# = 2 and CTIME = T
O_DATE('18-JAN-2000 12:25:28', 'DD-MON-YYYY HH24:MI:SS') and MTIME = TO_DATE('18
-JAN-2000 12:25:28', 'DD-MON-YYYY HH24:MI:SS') and STIME = TO_DATE('18-JAN-2000
12:25:28', 'DD-MON-YYYY HH24:MI:SS') and STATUS = 1 and REMOTEOWNER IS NULL and
LINKNAME IS NULL and FLAGS = 0 and ROWID = 'AAAAASAABAAAGXkAAA';

NOTE:  ctime = timestamp when the table was created
       mtime = timestamp for last DDL against the table

       Do not confuse the timestamp associated with the scn for the drop table 
       with the timestamps in obj$ for object create and modification.

SQL> select username from dba_users where user_id = 38;

USERNAME
------------------------------
TEST


Summary: 
========

At this point we know that table TEST.TAB1 (3 columns) was dropped at 
SCN 5012065 and time 2000-JAN-18 12:36:23.  This information can be used for
point-in-time recovery (PITR) of an unintentionally dropped object following 
the steps in Note:96197.1.


Search Words:
=============

Log Miner

 

 Related


Products
  • Oracle Database Products > Oracle Database > Oracle Database > Oracle Server - Enterprise Edition
  • Oracle Database Products > Oracle Database > Oracle Database > Oracle Server - Personal Edition
  • Oracle Database Products > Oracle Database > Oracle Database > Oracle Server - Standard Edition

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值