oracle 恢复tab$,删除tab$恢复1

-//网上提到许多删除tab$的案例,主要原因在于没有从官方正规渠道下载oracle版本,还有一些来自工具里面带有一些脚本删除tab$记录.

--//首先我并不知道许多人的恢复方法,仅仅简单提到恢复数据字典,我想到既然是删除,反向的操作就是恢复.也就是恢复tab$记录.

--//在我开始尝试时,我发现遇到的问题比原来想像的要复杂.tab$是CLUSTER C_OBJ#的一个表.本身cluster table的结果就与普通

--//堆表的结构不一样,还有可能遇到行链接和行迁移的情况.

--//这也是我最近许多帖子关于cluster table等方面的内容.

--//自己也尝试恢复看看.

1.环境:

SCOTT@book> @ ver1

PORT_STRING                    VERSION        BANNER

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

x86_64/Linux 2.4.xx            11.2.0.4.0     Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production

SCOTT@book> column SQL_TEXT format a100

SCOTT@book> select * from (select * from SYS.BOOTSTRAP$ order by line#) where rownum<=5;

LINE#       OBJ# SQL_TEXT

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

-1         -1 8.0.0.0.0

0          0 CREATE ROLLBACK SEGMENT SYSTEM STORAGE (  INITIAL 112K NEXT 56K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO

0 EXTENTS (FILE 1 BLOCK 128))

2          2 CREATE CLUSTER C_OBJ#("OBJ#" NUMBER) PCTFREE 5 PCTUSED 40 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL

136K NEXT 200K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 2 EXTENTS (FILE 1 BLOCK 144))

SIZE 800

3          3 CREATE INDEX I_OBJ# ON CLUSTER C_OBJ# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT

1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 3 EXTENTS (FILE 1 BLOCK 168))

4          4 CREATE TABLE TAB$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL,"FILE#" NUMBER NOT

NULL,"BLOCK#" NUMBER NOT NULL,"BOBJ#" NUMBER,"TAB#" NUMBER,"COLS" NUMBER NOT NULL,"CLUCOLS" NUMBER,"

PCTFREE$" NUMBER NOT NULL,"PCTUSED$" NUMBER NOT NULL,"INITRANS" NUMBER NOT NULL,"MAXTRANS" NUMBER NO

T NULL,"FLAGS" NUMBER NOT NULL,"AUDIT$" VARCHAR2(38) NOT NULL,"ROWCNT" NUMBER,"BLKCNT" NUMBER,"EMPCN

T" NUMBER,"AVGSPC" NUMBER,"CHNCNT" NUMBER,"AVGRLN" NUMBER,"AVGSPC_FLB" NUMBER,"FLBCNT" NUMBER,"ANALY

ZETIME" DATE,"SAMPLESIZE" NUMBER,"DEGREE" NUMBER,"INSTANCES" NUMBER,"INTCOLS" NUMBER NOT NULL,"KERNE

LCOLS" NUMBER NOT NULL,"PROPERTY" NUMBER NOT NULL,"TRIGFLAG" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,

"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE (  OBJNO 4 TA

BNO 1) CLUSTER C_OBJ#(OBJ#)

--//sys.tab$表是cluster table C_OBJ#下的一个表.OBJ#=2

SELECT ROWNUM -1 rn , a.*

FROM (  SELECT *

FROM dba_objects

WHERE owner = 'SYS' AND data_object_id = 2

ORDER BY object_id) a;

RN OWNER OBJECT_NAME SUBOBJECT_ OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED             LAST_DDL_TIME       TIMESTAMP           STATUS  T G S  NAMESPACE EDITION_NAME

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

0 SYS   C_OBJ#                         2              2 CLUSTER     2013-08-24 11:37:35 2013-08-24 11:37:35 2013-08-24:11:37:35 VALID   N N N          5

1 SYS   TAB$                           4              2 TABLE       2013-08-24 11:37:35 2013-08-24 11:47:37 2013-08-24:11:37:35 VALID   N N N          1

2 SYS   CLU$                           5              2 TABLE       2013-08-24 11:37:35 2013-08-24 11:37:35 2013-08-24:11:37:35 VALID   N N N          1

3 SYS   IND$                          19              2 TABLE       2013-08-24 11:37:35 2013-08-24 11:47:37 2013-08-24:11:37:35 VALID   N N N          1

4 SYS   ICOL$                         20              2 TABLE       2013-08-24 11:37:35 2013-08-24 11:47:37 2013-08-24:11:37:35 VALID   N N N          1

5 SYS   COL$                          21              2 TABLE       2013-08-24 11:37:35 2013-08-24 11:52:40 2013-08-24:11:37:35 VALID   N N N          1

6 SYS   LOB$                          80              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:47:37 2013-08-24:11:37:36 VALID   N N N          1

7 SYS   COLTYPE$                      83              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:47:37 2013-08-24:11:37:36 VALID   N N N          1

8 SYS   SUBCOLTYPE$                   86              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

9 SYS   NTAB$                         88              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

10 SYS   REFCON$                       92              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

11 SYS   OPQTYPE$                      95              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

12 SYS   ICOLDEP$                     114              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

13 SYS   VIEWTRCOL$                   174              2 TABLE       2013-08-24 11:37:36 2013-08-24 11:37:36 2013-08-24:11:37:36 VALID   N N N          1

14 SYS   LIBRARY$                     252              2 TABLE       2013-08-24 11:37:39 2013-08-24 11:37:39 2013-08-24:11:37:39 VALID   N N N          1

15 SYS   ASSEMBLY$                    253              2 TABLE       2013-08-24 11:37:39 2013-08-24 11:37:39 2013-08-24:11:37:39 VALID   N N N          1

16 SYS   ATTRCOL$                     512              2 TABLE       2013-08-24 11:37:43 2013-08-24 11:37:43 2013-08-24:11:37:43 VALID   N N N          1

17 SYS   TYPE_MISC$                   517              2 TABLE       2013-08-24 11:37:43 2013-08-24 11:37:43 2013-08-24:11:37:43 VALID   N N N          1

18 rows selected.

--//可以发现tab$仅仅是cluster table中的1个.而是是第1个表(从0算起,0是cluster table)

2.如何tab$表被全部删除,自然导致数据库无法启动:

--//如何修复呢?

--//CLUSTER C_OBJ#的段头在dba 1,144.

SCOTT@book> select * from dba_extents where owner='SYS' and segment_name='C_OBJ#';

OWNER SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID   BYTES BLOCKS RELATIVE_FNO

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

SYS   C_OBJ#       CLUSTER      SYSTEM                  0       1      144   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  1       1      152   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  2       1      160   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  3       1     3336   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  4       1     4392   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  5       1     5424   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  6       1     6152   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  7       1     7264   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  8       1     7912   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                  9       1     8464   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 10       1     8496   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 11       1     8520   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 12       1     8552   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 13       1     8560   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 14       1     8600   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 15       1     8624   65536      8            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 16       1     8704 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 17       1     9856 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 18       1    13312 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 19       1    17792 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 20       1    22400 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 21       1    31488 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 22       1    65920 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 23       1    73984 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 24       1    77824 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 25       1    86016 1048576    128            1

SYS   C_OBJ#       CLUSTER      SYSTEM                 26       1    94208 1048576    128            1

27 rows selected.

--//system的表空间是mssm,bbed可以查看这种文件的段头.这些信息记录在

BBED> p /d dba 1,144  ktetb

struct ktetb[0], 8 bytes                    @108

ub4 ktetbdba                             @108      4194449

ub4 ktetbnbk                             @112      7

--//这里不算段头,记录数据部分.仅仅占7块.

struct ktetb[1], 8 bytes                    @116

ub4 ktetbdba                             @116      4194456

ub4 ktetbnbk                             @120      8

struct ktetb[2], 8 bytes                    @124

ub4 ktetbdba                             @124      4194464

ub4 ktetbnbk                             @128      8

struct ktetb[3], 8 bytes                    @132

ub4 ktetbdba                             @132      4197640

ub4 ktetbnbk                             @136      8

struct ktetb[4], 8 bytes                    @140

ub4 ktetbdba                             @140      4198696

ub4 ktetbnbk                             @144      8

..

struct ktetb[25], 8 bytes                   @308

ub4 ktetbdba                             @308      4280320

ub4 ktetbnbk                             @312      128

struct ktetb[26], 8 bytes                   @316

ub4 ktetbdba                             @316      4288512

ub4 ktetbnbk                             @320      128

--//我程序中使用的别名如下:

$ alias zdate='date +'\''%Y/%m/%d %T'\'''

$ export RLWRAP=$(which rlwrap)

$ type rlbbed

rlbbed is a function

rlbbed ()

{

cd /home/oracle/bbed;

$RLWRAP -s 9999 -c -r -i -f /usr/local/share/rlwrap/bbed $ORACLE_HOME/bin/bbed parfile=bbed.par cmdfile=cmd.par

}

--//关于bbed配置看相关文档.我下面有一些代码使用cut直接取对应位置的数据,可能width(宽度)设置要与我脚本保持一致.

$ cat cmd.par

set count 64

set width 160

$ cat bbed.par

blocksize=8192

listfile=$HOME/bbed/filelist.txt

mode=edit

PASSWORD=blockedit

SPOOL=Y

--//filelist.txt文件通过select file#||' '||name c100 from v$dbfile order by file#;生成.

--//首先确定扫描那些块的脚本.

/bin/rm /home/oracle/zzz430/bbed/scan*.txt

cd /home/oracle/zzz430/bbed

echo "process 1 start : `zdate` scan dba 1,144 ,  create scan1.txt about ktetbdba,ktetbnbk"

echo "p /d dba 1,144"  ktetb | rlbbed | egrep 'ktetbdba|ktetbnbk' | cut -c8-16,55- |tr " " "=" | paste -d ";" - - > scan1a.txt

high_water=`echo p /d dba 1,144 ktech.hwmark_ktech.blkno_ktehw | rlbbed | grep blkno_ktehw | cut -c60- | tr -d " " `

sed "\$s/ktetbnbk=.*$/ktetbnbk=$high_water/" scan1a.txt > scan1.txt

read -p "process 1 finish: `zdate`,enter continue..."

--//结果保存scan1.txt

--//也就是从dba=4194449开始,扫描7块. 从4194456开始,扫描8块....如此到结束。

--//注意仅仅扫描到高水位下的块.

3.分析扫描块的情况:

BBED> set dba 4194449

DBA             0x00400091 (4194449 1,145)

BBED> p /d kdbt[1]

struct kdbt[1], 4 bytes                     @110

sb2 kdbtoffs                             @110      8

sb2 kdbtnrow                             @112      7

--//按照前面的查询,仅仅kdbt[1]记录相关表sys.tab$的记录信息,从偏移8(即*kdbr[8])开始,共有7条记录.

BBED> x /rnnnnnnnnnnnnncnnnnnnnntnnnnnnnnnncct *kdbr[8]

rowdata[7430]                               @7884

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

flag@7884: 0x6c (KDRHFL, KDRHFF, KDRHFH, KDRHFC)

lock@7885: 0x00

cols@7886:   31

col    0[2] @7888: 2

col    1[1] @7891: 0

col    2[2] @7893: 1

col    3[3] @7896: 144

col    4[2] @7900: 2

col    5[2] @7903: 4

col    6[2] @7906: 14

col    7[2] @7909: 1

col    8[1] @7912: 0

col    9[1] @7914: 0

col   10[1] @7916: 0

col   11[1] @7918: 0

col   12[3] @7920: 529

col  13[38] @7924: --------------------------------------

col   14[3] @7963: 7789

col   15[3] @7967: 1442

col   16[1] @7971: 0

col   17[1] @7973: 0

col   18[1] @7975: 0

col   19[2] @7977: 32

col   20[1] @7980: 0

col   21[1] @7982: 0

col   22[7] @7984: 2017-02-03 22:00:18

col   23[3] @7992: 7789

col   24[0] @7996: *NULL*

col   25[0] @7997: *NULL*

col   26[2] @7998: 14

col   27[2] @8001: 14

col   28[3] @8004: 1024

col   29[1] @8008: 0

col   30[1] @8010: 0

..

BBED> x /rnnnnnnnnnnnnncnnnnnnnntnnnnnnnnnncct *kdbr[14]

rowdata[6684]                               @7138

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

flag@7138: 0x6c (KDRHFL, KDRHFF, KDRHFH, KDRHFC)

lock@7139: 0x02

cols@7140:   31

ckix@7141:    7

col    0[2] @7142: 2

col    1[1] @7145: 0

col    2[2] @7147: 1

col    3[3] @7150: 144

col    4[2] @7154: 2

col    5[2] @7157: 3

col    6[2] @7160: 34

col    7[2] @7163: 1

col    8[1] @7166: 0

col    9[1] @7168: 0

col   10[1] @7170: 0

col   11[1] @7172: 0

col   12[3] @7174: 529

col  13[38] @7178: --------------------------------------

col   14[3] @7217: 5066

col   15[3] @7221: 1442

col   16[1] @7225: 0

col   17[1] @7227: 0

col   18[1] @7229: 0

col   19[2] @7231: 91

col   20[1] @7234: 0

col   21[1] @7236: 0

col   22[7] @7238: 2017-02-22 22:00:13

col   23[3] @7246: 5066

col   24[0] @7250: *NULL*

col   25[0] @7251: *NULL*

col   26[2] @7252: 34

col   27[2] @7255: 34

col   28[3] @7258: 1024

col   29[1] @7262: 0

col   30[1] @7264: 0

--//获取tab$的记录偏移以及数量.使用scan2.sh脚本.

echo "process 2 start : `zdate` scan block , get kdbtnrow,kdbtoffs ang grep kdbtnrow=0"

cat scan1.txt | while read i

do

eval $i

#echo $ktetbdba  $ktetbnbk

for ((j=1; j<=$ktetbnbk ; j++))

do

echo -n "dba=$ktetbdba;" >> scan2a.txt

echo "p /d dba $ktetbdba offset 0 kdbt[1]" | rlbbed | egrep 'kdbtoffs|kdbtnrow' |  cut -c8-16,55- |tr " " "=" | paste -d ";" - - >> scan2a.txt

ktetbdba=$[ ktetbdba + 1 ]

#echo $ktetbdba

done

done

grep -v kdbtnrow=0 scan2a.txt > scan2.txt

read -p "process 2 finish: `zdate`,enter continue..."

..

--//生成scan2a.txt,过滤掉kdbtnrow=0.结果保存scan2.txt

$ head scan2.txt

dba=4194449;kdbtoffs=8;kdbtnrow=7

dba=4194450;kdbtoffs=8;kdbtnrow=5

dba=4194451;kdbtoffs=9;kdbtnrow=6

dba=4194452;kdbtoffs=10;kdbtnrow=9

dba=4194453;kdbtoffs=10;kdbtnrow=10

dba=4194454;kdbtoffs=10;kdbtnrow=10

dba=4194455;kdbtoffs=10;kdbtnrow=10

dba=4194456;kdbtoffs=10;kdbtnrow=10

dba=4194457;kdbtoffs=10;kdbtnrow=10

dba=4194458;kdbtoffs=7;kdbtnrow=7

3.生成修改记录flag偏移的脚本:

echo "process 3 start : `zdate` scan block , create bbed'script scan3_bbed.txt for modify delete of flag  and create scan4a.txt about block of ckix "

cat scan2.txt | while read i

do

eval $i

begin=$kdbtoffs

end=$[ kdbtoffs + kdbtnrow -1 ]

#  echo $dba $kdbtoffs $kdbtnrow  $begin $end

kdbr_size=`echo map dba $dba| rlbbed | grep "sb2 kdbr" | sed -e "s/^.*\[//" -e "s/].*$//" `

while [ $begin -le $end ]

do

kdbr_off=`echo p dba $dba offset 0 kdbr | rlbbed | grep "\[$begin\]" | cut -c55-`

if [ $kdbr_off -gt $kdbr_size ]

then

echo "x /rc dba $dba *kdbr[$begin]" | rlbbed | grep '^flag@' | grep KDRHFD | sed -e 's/^flag@/offset=/' -e 's/ (.*)//' -e 's/: /;value=/' | tr -d " " | while read k

#echo "x /rc dba $dba *kdbr[$begin]" | rlbbed | grep '^flag@' | sed -e 's/^flag@/offset=/' -e 's/ (.*)//' -e 's/: /;value=/' | tr -d " " | while read k

do

eval $k

#echo $dba $offset $value

value=`printf "0x%x" $(( value - 0x10  )) `

echo "assign /x dba $dba offset $offset = $value " >> scan3_bbed.txt

done

#  if not found ckix@ and  found flag=0x7c , then ckix_value=0, and do not process chained row.

echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | grep "^ckix@" | sed -e "s/^ckix/dba=$dba;/" -e  's/@.*:/ckix_value=/' | tr -d " " >> scan4a.txt

echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^ckix@" > /dev/null

if [ $? -eq 1 ]

then

echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^^flag@.*: 0x7c" > /dev/null

if [ $? -eq 0 ]

then

echo "dba=$dba;ckix_value=0" >> scan4a.txt

fi

fi

fi

begin=$[ begin + 1 ]

done

done

read -p "process 3 finish: `zdate`,enter continue..."

--//记录的偏移量如果小于kdbr_size,这些是覆盖的记录可能无法恢复,必须跳过.

--//注意仅仅过滤包含KDRHFD标识的记录需要修改,生成修改偏移的脚本保存在scan3_bbed.txt.

--//修改flag 使用当前值 减去 0x10.

--//并且保存dba,ckix位置的脚本在scan4a.txt,注意使用注解部分,仅仅过滤KDRHFD标志的记录.(写脚本时tab$记录还没有删除)

--//注:如果过滤不存在ckix,使用ckix_value=0替代,如果存在行迁移,跳过不处理.

$ head scan3_bbed.txt

assign /x dba 4194449 offset 7884 = 0x5c

assign /x dba 4194449 offset 7756 = 0x5c

assign /x dba 4194449 offset 7632 = 0x5c

assign /x dba 4194449 offset 7512 = 0x5c

assign /x dba 4194449 offset 7388 = 0x5c

assign /x dba 4194449 offset 7266 = 0x5c

assign /x dba 4194449 offset 7138 = 0x5c

assign /x dba 4194450 offset 509 = 0x5c

assign /x dba 4194450 offset 7882 = 0x5c

assign /x dba 4194450 offset 7756 = 0x5c

--//注:实际上正常恢复大部分值是0x6c,删除前是0x7c.

$ head scan4a.txt

dba=4194449;ckix_value=0

dba=4194449;ckix_value=1

dba=4194449;ckix_value=2

dba=4194449;ckix_value=4

dba=4194449;ckix_value=5

dba=4194449;ckix_value=6

dba=4194449;ckix_value=7

dba=4194450;ckix_value=1

dba=4194450;ckix_value=3

dba=4194450;ckix_value=4

4.修改mref_offset标识:

echo "process 4 start : `zdate` create bbed's scan4_bbed.txt for modify cluster of mref of value "

sort scan4a.txt | uniq > scan4b.txt

cat scan4b.txt | while read i

do

eval $i

#echo $dba  $ckix_value

echo -n "dba=$dba;" >> scan4c.txt

echo "x /rn dba $dba *kdbr[$ckix_value]" | rlbbed | egrep "^kref@|^mref@" | sed -e "s/@/_offset=/" -e "s/:/;value=/" | tr -d " " | paste -d ";" - -  >> scan4c.txt

done

sed -e 's/;$/;mref_offset=0;value=0/' -e 's/value=/valuek=/' scan4c.txt > scan4.txt

cat scan4.txt | while read i

do

eval $i

# echo $dba $kref_offset $valuek $mref_offset $value

if [ $mref_offset -eq 0 ]

then

mref_offset=$[ $kref_offset+ 2 ]

fi

valuem=$[ value + 1 ]

if [ $valuem -lt $valuek ]

then

echo "assign dba $dba offset $mref_offset = $valuem" >> scan4m_bbed.txt

else

echo "assign dba $dba offset $mref_offset = $valuek" >> scan4k_bbed.txt

fi

done

read -p "process 4 finish: `zdate`,enter continue..."

--//注:如果没有mref表示的情况其值等于0.实际上这步可以不做修复.对于读取tab$表没有问题的.

--//不做,verify类似如下错误.

Block Checking: DBA = 4288536, Block Type = KTB-managed data block

data header at 0x7f865724125c

kdbchk:  key comref count wrong

keyslot=8

Block 94232 failed with check code 6121

5.建立sum apply脚本:

echo "process 5 start : create bbed's scan5_bbed.txt for sum apply"

sed -e 's/^dba=/sum apply dba /' -e 's/;.*$//' scan2.txt > scan5_bbed.txt

read -p "process 5 finish: `zdate`,enter continue..."

6.注意问题.

--//恢复记录后,tab$的索引I_TAB1与表tab$存在不一致的情况.

SYS@book> select rowid,a.* from SYS.BOOTSTRAP$ a where a.sql_text like '%I_TAB1%';

ROWID                   LINE#       OBJ# SQL_TEXT

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

AAAAA7AABAAAAILAAJ         33         33 CREATE INDEX I_TAB1 ON TAB$(BOBJ#) PCTFREE 10 INITRANS 2 MAX

TRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAX

EXTENTS 2147483645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BL

OCK 312))

--//必须禁用这个索引.

SYS@book> @ rowid AAAAA7AABAAAAILAAJ

OBJECT       FILE      BLOCK        ROW ROWID_DBA            DBA                  TEXT

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

59          1        523          9   0x40020B           1,523                alter system dump datafile 1 block 523 ;

BBED> x /rnnc dba 1,523 *kdbr[9]

rowdata[1269]                               @4910

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

flag@4910: 0x2c (KDRHFL, KDRHFF, KDRHFH)

lock@4911: 0x01

cols@4912:    3

col    0[2] @4913: 33

col    1[2] @4916: 33

col  2[189] @4919: CREATE INDEX I_TAB1 ON TAB$(BOBJ#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483

645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BLOCK 312))

--//设置flag=3c,表示删除.

assign /x dba 1,523 offset 4910= 0x3c

7.剩下的就是测试.但愿OK.

--//太长,另外写一篇blog具体操作过程.另外对于已经出问题的系统,可能要设置_system_trig_enabled=false,job_queue_processes=0启动数据库.可能还有一些

--//细节需要注意.

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
不小心Truncate表的事情也是有的, 其中大部份时因为工具连错了库, 从儿跑错了角本. 遇到这种事情而没有备份时怎么办呢? 首先要停止数据库, 将这个表所在的表空间的文件拷贝出来, 因为Oracle在Truncate只时将相应Segment的第一个块格式化掉了, 而后面的都还存在, 到下次用时到才真正地重新格式化. 下面来讲一个Truncate表后进行恢复的例子: SQL> CREATE TABLE T_TRUNCATE AS SELECT * FROM TAB; Table created. SQL> SELECT COUNT(*) FROM T_TRUNCATE; COUNT(*) ---------- 14 SQL> ALTER SYSTEM CHECKPOINT; System altered. SQL> TRUNCATE TABLE T_TRUNCATE; Table truncated. SQL> ALTER SYSTEM CHECKPOINT; System altered. 在Truncate时只是Segment Header格式化了, 并将Data Object ID换成一个新的值, 我们可以在AUL中用DESC命令来查看: AUL> desc anysql.t_truncate Storage(OBJ#=9976 OBJD=9977 TS=4 FILE=4 BLOCK=5235 CLUSTER=0) No. SEQ INT Column Name Type --- --- --- ----------------------------- ---------------- 1 1 1 TNAME VARCHAR2(30) NOT NULL 2 2 2 TABTYPE VARCHAR2(7) 3 3 3 CLUSTERID NUMBER 要恢复这个表的数据, 首先要在AUL中运行SCAN EXTENT命令, 因为Segment Header被格式化了, 所以Extent Map也可能丢失, 而Scan Extent则将扫描整个数据文件并将Extent分配信息写入AULEXT.TXT文件: AUL> SCAN EXTENT FILE 4 2006-12-18 21:32:10 2006-12-18 21:32:24 恢复的关键是要获得这个表原来的Data Object ID, 在这个例子中我在Truncate表后什么也没有做就关闭数据库进行恢复了. 从上面的DESC命令可以看出表的Segment Header是(4,5235), 而新的Data Object ID是9977, 老的Data Object ID我们可以从Segment Header的后面一个数据块中得到, 如果这个表有几个Free List Group, 则可能还要再后面几个块. 用AUL的ORADUMP命令来看一下后面一个块: AUL> ORADUMP FILE 4 BLOCK 5236 RDBA=0x01001474(4/5236)=16782452,type=0x06,fmt=0xa2,seq=0x02,flag=0x04 seg/obj=0x000026f8=9976,csc=0x0000.0006caf5,itc=3,typ=1 - DATA FLG=0x32, fls=0, nxt=0x01001471(4/5233)=16782449 ...... 可以看到原来的Data Object ID是9976, 现在可以恢复了, 先不指定原来的Data Object ID试试? AUL> unload table anysql.t_truncate; 2006-12-18 21:33:37 Unload OBJD=9977 FILE=4 BLOCK=5235 CLUSTER=0 ... 2006-12-18 21:33:37 接下来指定原来的Data Object ID, 再试试? AUL> unload table anysql.t_truncate object 9976; 2006-12-18 21:33:45 Unload OBJD=9976 FILE=4 BLOCK=5235 CLUSTER=0 ... P_MV_FACT_SALES|TABLE TIME_DIM|TABLE FACT_SALES|TABLE MV_FACT_SALES|TABLE SEG$|TABLE NUMTEST|TABLE T_OBJECTS|TABLE T_LOBTEST|TABLE T_INCLOB|TABLE CF_XXK|TABLE T_TESTDMP|TABLE T_CLOBDEMO|TABLE T_BLOBDEMO|TABLE T_TRUNCATE|TABLE 2006-12-18 21:33:45 可以看到14条数据全回来了, 当然数据库是复杂的, 如果是一个很大的表, 还是不能保证可以100%恢复的. 最近至少看到二次错误地截断(Truncate)表的例子, 并在网上询问如何恢复, 在这儿我给出AUL/MyDUL的解决方案, 下面是我用的一个测试表: ASQL> DESC TRUNCDEMO NO# NAME NULLABLE TYPE --- ----------------- -------- ------------ 1 COL1 VARCHAR2(20) ASQL> SELECT * FROM TRUNCDEMO; COL1 ----- ROW 1 ROW 2 2 rows returned. 接下来我们来截断表, 其实这个操作只是重新格式化了段头块(Segment Header), 并分配一个新的数据对象号(Data Object ID), 当然空间分配信息也改了, 除非加了重用空间选项(Reuse Storage). 来看一下这个操作的前后变化: ASQL> SELECT DATA_OBJECT_ID, OBJECT_NAME FROM USER_OBJECTS; DATA_OBJECT_ID OBJECT_NAME -------------- ----------- 13676 TRUNCDEMO 1 rows returned. ASQL> truncate table truncdemo; Truncate Table Succeed. ASQL> SELECT DATA_OBJECT_ID, OBJECT_NAME FROM USER_OBJECTS; DATA_OBJECT_ID OBJECT_NAME -------------- ----------- 13677 TRUNCDEMO 1 rows returned. 由于在System表空间中已经记录了新的信息, 因此用当前的System信息是不能恢复过来的,在AUL/MyDUL中可以当作没有System时的情况来处理,在下面的命令中, 我们用Truncate后的数据对象号就不能进行恢复, 而使用Truncate以前的就可以, 当然空间不能被重新利用了是恢复的前提. AUL> unload object 13676 column varchar file 4; 2006-09-18 22:38:58 ROW 1 ROW 2 2006-09-18 22:39:04 AUL> unload object 13677 column varchar file 4; 2006-09-18 22:39:10 2006-09-18 22:39:10 AUL> 因此在意外发生Truncate后, 如果没有备份可以恢复, 首先要做的事是备份一下当前的文件, 免得空间被重用. 而Truncate之前的数据对象号在AUL/MyDUL中是很容易找出来的. 到此已经说明了如何恢复Truncate表了. 跟据原理可以创建一个恢复包Recover_Truncate_Data,然后我们可以做个实验进行验证恢复效果如何: 第一步:创建表 create table truntab1 as select * from dba_objects; 第二步:查询表中记录数 select count(*) from truntab1; --72622 第三步:truncate表中业务数据 truncate table truntab1; 第四步:确认表中记录数为零 select count(*) from truntab1; -- 0 第五步:设置恢复前环境变量 set serveroutput on size 10000000 --//设置大点,默认为2000 bytes exec dbms_output.enable(999999999999999999999); --//默认为2000 bytes 注意:如果不不进行设置,为报PLSQL ORA-20000: ORU-10027: buffer overflow, limit of 10000 第六步:实施truncate表中数据恢复 declare tgtowner varchar2(30); tgttable varchar2(30); datapath varchar2(4000); datadir varchar2(30); rects varchar2(30); recfile varchar2(30); rstts varchar2(30); rstfile varchar2(30); blksz number; rectab varchar2(30); rsttab varchar2(30); copyfile varchar2(30); begin tgtowner := 'SYS'; --指定表名的属用户 tgttable := 'TRUNTAB1'; --指定需要恢复的表名 datapath := 'D:\app\Administrator\oradata\lmis\'; --数据文件所在位置 datadir := 'FY_DATA_DIR'; Recover_Truncate_data.prepare_files(tgtowner, tgttable, datapath, datadir, rects, recfile, rstts, rstfile, blksz); Recover_Truncate_data.fill_blocks(tgtowner, tgttable, datadir, rects, recfile, rstts, 8, tgtowner, tgtowner, rectab, rsttab, copyfile); Recover_Truncate_data.recover_table(tgtowner, tgttable, tgtowner, rectab, tgtowner, rsttab, datadir, datadir, recfile,datadir, copyfile, blksz); end; 第七步:查看输出内容和构造表名: 15:32:44: Directory Name: FY_DATA_DIR4 15:32:45: Recover Tablespace: FY_REC_DATA4; Data File: FY_REC_DATA4.DAT 15:32:46: Restore Tablespace: FY_RST_DATA4; Data File: FY_RST_DATA4.DAT 15:32:48: Recover Table: SYS.TRUNTAB1$2 15:32:48: Restore Table: SYS.TRUNTAB1$$2 15:33:04: [fill_blocks] Data Blocks formatted. 15:33:05: [copy_file] begin copy file: FY_DATA_DIR4\FY_REC_DATA4.DAT => FY_DATA_DIR4\FY_REC_DATA_COPY.DAT 15:33:05: [copy_file] completed. 15:33:05: Copy file of Recover Tablespace: FY_REC_DATA_COPY.DAT 15:33:05: begin to recover table SYS.TRUNTAB1 15:33:19: [restore_table] Trying to restore data to SYS.TRUNTAB1$$2 15:33:20: [restore_table] Expected Records in this round: 411 15:33:20: [restore_table] 411 records recovered 此处省略N行输出............................................ 15:33:44: [restore_table] Expected Records in this round: 0 15:33:44: [restore_table] 0 records recovered 15:33:44: 1033 truncated data blocks found. 15:33:44: 72622 records recovered in backup table SYS.TRUNTAB1$$2 15:33:44: Recovery completed. PL/SQL procedure successfully completed 从红色字体可以看出,恢复72622条,刚好是truncate前业务表中记录数,恢复临时表为:SYS.TRUNTAB1$$2 第七步:查看输出内容和构造表名: insert into truntab1 select * from SYS.TRUNTAB1$$2 第八步:验证数据是否完全恢复 select count(*) from truntab1; --72622 至此,truncate掉的数据成功恢复,并且此方法也可以恢复drop table tablename purge删除的数据, 第九步:清理恢复产生的表空间和数据文件 特别提醒:恢复完成后,该方法会在数据库中产生一个表空间:FY_RST_DATA*,恢复一次产生一个,记得及时清理!否则会导致服务器RMAN备份失败ORA-19566 超出损坏块限制(切记) truncate原理: ? ? ? ?TRUNCATE不会逐个清除用户数据块上的数据,而仅仅重置数据字典和元数据块上的元数据(如存储段头和扩展段图)。也就是说,此时,其基本数据并未被破坏,而是被系统回收、等待被重新分配————因此,要恢复被TRUNCATE的数据,需要及时备份其所在的数据文件。 ? ? 方法:用存储过程包Fy_Recover_Data ? ? 它是利用Oracle表扫描机制、数据嫁接机制恢复TRUNCATE或者损坏数据的工具包,这个包是由行内有影响力的DBA大师黄炜先生通过PLSQL编写的,再这里再次感谢他的无私技术分享。Fy_Recover_Data去本文附近中下载 好了,闲话少说,下面通过oracle数据库中scott用户自带的emp表做测试: 步骤1:先把Fy_Recover_Data包拷贝到oracle相关目录下 步骤2:在scott用户下创建test_emp表: SQL> conn scott/tiger; Connected. SQL> select * from tab; TNAME ? ? ? TABTYPE CLUSTERID ------------------------------ ------- ---------- BONUS ? ? ? TABLE DEPT ? ? ? TABLE EMP ? ? ? ? ? ? ? ?TABLE SALGRADE ? ? ? TABLE SQL> select count(*) from emp; ? COUNT(*) ---------- 14 SQL> create table test_emp ?as select * from emp; Table created. SQL> select count(*) from test_emp; ? COUNT(*) ---------- 14 步骤3:用truncate删除test_emp表: SQL> truncate table test_emp; Table truncated. SQL> select count(*) from test_emp; ? COUNT(*) ---------- 0 步骤4:在linux中的oracle用户下解压FY_Recover_Data.zip包 $ unzip FY_Recover_Data.zip Archive: ?FY_Recover_Data.zip ? inflating: FY_Recover_Data.SQL? 步骤5:恢复 1)在sys用户下执行存储过程 SQL> @/home/oracle/FY_Recover_Data.SQL Package created. Package body created. 2)查看test_emp表在数据文件中的目录 SQL> select file_name from dba_data_files f, dba_tables t where t.owner='SCOTT' and t.table_name='TEST_EMP' and t.tablespace_name = f.tablespace_name; FILE_NAME -------------------------------------------------------------------------------- /u03/oracle/oradata/WUTONG/datafile/o1_mf_users_cx3xt940_.dbf 3)通过脚本恢复,可以用sqlplus命令行或者plsql developer执行 declare ? ? ? tgtowner varchar2(30); ? ? ? tgttable varchar2(30); ? ? ? datapath varchar2(4000); ? ? ? datadir varchar2(30); ? ? ? rects varchar2(30); ? ? ? recfile varchar2(30); ? ? ? rstts varchar2(30); ? ? ? rstfile varchar2(30); ? ? ?blksz number; ? ? ?rectab varchar2(30); ? ? ?rsttab varchar2(30); ? ? ?copyfile varchar2(30); ? ?begin ? ? ?tgtowner := 'SCOTT'; --table owner ? ? ?tgttable := 'TEST_EMP'; ?--table name ? ? ?datapath := '/u03/oracle/oradata/WUTONG/datafile/'; ? ?--必须和test.t1表所在的数据文件的目录相同 ? ? ?datadir := 'FY_DATA_DIR'; ? ? ? ?--oracle中目录的名字,可以修改 ? ? ?Fy_Recover_data.prepare_files(tgtowner, tgttable, datapath, datadir, rects, recfile, rstts, rstfile, blksz); ? ? ?Fy_Recover_data.fill_blocks(tgtowner, tgttable, datadir, rects, recfile, rstts, 8, tgtowner, tgtowner, rectab, rsttab, copyfile); ? ? ?Fy_Recover_data.recover_table(tgtowner, tgttable, tgtowner, rectab, tgtowner, rsttab, datadir, datadir, recfile,datadir, copyfile, blksz); ? ?end; ? ?以上SQL脚本产生2个表空间(2个数据文件),还有1个copy文件。 4)切换到scott用户下查看会发现多了些不一样以test_emp的表,这时找到相关有数据的表,把数据插入原表test_emp SQL> conn scott/tiger Connected. SQL> select * from tab; TNAME ? ? ? TABTYPE CLUSTERID ------------------------------ ------- ---------- BONUS ? ? ? TABLE DEPT ? ? ? TABLE EMP ? ? ? TABLE SALGRADE ? ? ? TABLE TEST_EMP ? ? ? TABLE TEST_EMP$ ? ? ? TABLE TEST_EMP$$ ? ? ? TABLE 7 rows selected. SQL> insert into test_emp select * from TEST_EMP$$; 14 rows created. SQL> commit; Commit complete. SQL> select count(*) from test_emp; ? COUNT(*) ---------- 14 当你看到这一步的时候,说明truncate的表已经完全恢复了,恭喜你数据恢复成功!紧张的压力随之而释放,脸上露出灿烂的笑容和自豪感(做DBA很辛苦,数据库能保持正常运行,DBA在幕后做了大量的工作,有时是不会不被公司其他人理解的。。。。。) 步骤6:恢复数据后,把恢复时产生的2个表空间删除,再删除对应数据文件 SQL> conn / as sysdba Connected. SQL> select name from v$datafile; NAME -------------------------------------------------------------------------------- /u03/oracle/oradata/WUTONG/datafile/o1_mf_system_cx3xt90z_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_sysaux_cx3xt930_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_undotbs1_cx3xt93b_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_users_cx3xt940_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_wutong_cx415lcj_.dbf /u03/oracle/oradata/WUTONG/datafile/FY_REC_DATA.DAT /u03/oracle/oradata/WUTONG/datafile/FY_RST_DATA.DAT 7 rows selected. SQL>?drop tablespace FY_REC_DATA INCLUDING CONTENTS; Tablespace dropped. SQL>?drop tablespace FY_RST_DATA INCLUDING CONTENTS; Tablespace dropped. SQL> select name from v$datafile; NAME -------------------------------------------------------------------------------- /u03/oracle/oradata/WUTONG/datafile/o1_mf_system_cx3xt90z_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_sysaux_cx3xt930_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_undotbs1_cx3xt93b_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_users_cx3xt940_.dbf /u03/oracle/oradata/WUTONG/datafile/o1_mf_wutong_cx415lcj_.dbf 然后去操作系统下把对应的数据文件删除即可 ---------------------
使用ODU恢复Truncate表ODUmanual ODU3月 15th, 2009 意外Truncate表的事情时有发生,ODU提供了方便的恢复Truncate表的功能。被Truncate的表,只要原来的空间没有被重用(即数据被覆盖),则数据都是可以恢复的。 如果发现一个表被意外地Truncate,而需要马上恢复。首先要做的就是关闭数据库,或者OFFLINE那个表所在的表空间,或者关闭所有应用。目的只有一个,确保空间不会被重用,数据不会被覆盖。 下面举例说明如何用ODU恢复被Truncate掉的表。 1. 建立测试的表DB_JJ_INFO_TEMP。 SQL> connect pdata/test 已连接。 SQL> create table DB_JJ_INFO_TEMP as select * from dba_objects; SQL> truncate table DB_JJ_INFO_TEMP; 2. 我们OFFLINE掉DB_JJ_INFO_TEMP表的表空间(实际上在实际的系统中,如果有比较多的活动,则表空间不容易被OFFLINE下来)。然后做一个Checkpoint,让ODU能够读到最新的数据字典数据。 SQL> select tablespace_name from user_tables where table_name='DB_JJ_INFO_TEMP'; TABLESPACE_NAME ------------------------------ PDATA SQL> alter tablespace PDATA offline; 表空间已更改。 SQL> alter system checkpoint; 系统已更改。 22=================================完善字典文件格式如下 control.txt文件中的数据格式为: 表空间号 文件号 相对文件号 文件名 块大小 是否大文件表空间 每列之间用空白分隔,可以只需要前四列,即块大小和是否大文件表空间可省略,块大小省略时,数据文件的默认块大小为config.txt中block_size的大小。下面是一个示例的数据: #ts #fno #rfno filename block_size bigfile 0 1 1 D:\ORACLE\ORADATA\XJ\SYSTEM01.DBF 4096 1 2 2 D:\ORACLE\ORADATA\XJ\UNDOTBS01.DBF 4096 3 3 3 D:\ORACLE\ORADATA\XJ\DRSYS01.DBF 4096 4 4 4 D:\ORACLE\ORADATA\XJ\EXAMPLE01.DBF 4096 5 5 5 D:\ORACLE\ORADATA\XJ\INDX01.DBF 4096 6 6 6 D:\ORACLE\ORADATA\XJ\ODM01.DBF 4096 7 7 7 D:\ORACLE\ORADATA\XJ\TOOLS03.DBF 4096 7 8 8 D:\ORACLE\ORADATA\XJ\TOOLS02.DBF 4096 9 9 9 D:\ORACLE\ORADATA\XJ\XDB01.DBF 4096 11 10 10 D:\ORACLE\ORADATA\XJ\TEST01.DBF 2048 14 11 11 D:\ORACLE\ORADATA\XJ\K16.DBF 16384 如果数据文件头是完好的,则ODU会自动从文件头里面获取表空间号,文件号,相对文件号,文件块大小等。表空间号,文件号和相对文件号可以写为0。 注意:ODU将检查control.txt文件中的第一个数据文件是否为SYSTEM表空间文件,所以要将SYSTEM表空间的第1个文件放在control.txt文件中的第一行。否则将不能自动获得数据字典数据。 3. 运行ODU,并unload数据字典。 ODU> unload dict get_bootstrap_dba: compat header size:12 CLUSTER C_USER# file_no: 1 block_no: 177 TABLE OBJ$ file_no: 1 block_no: 241 CLUSTER C_OBJ# file_no: 1 block_no: 49 CLUSTER C_OBJ# file_no: 1 block_no: 49 found IND$’s obj# 19 found IND$’s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3 found TABPART$’s obj# 230 found TABPART$’s dataobj#:230,ts#:0,file#:1,block#:3313,tab#:0 found INDPART$’s obj# 234 found INDPART$’s dataobj#:234,ts#:0,file#:1,block#:3377,tab#:0 found TABSUBPART$’s obj# 240 found TABSUBPART$’s dataobj#:240,ts#:0,file#:1,block#:3473,tab#:0 found INDSUBPART$’s obj# 245 found INDSUBPART$’s dataobj#:245,ts#:0,file#:1,block#:3553,tab#:0 found IND$’s obj# 19 found IND$’s dataobj#:2,ts#:0,file#:1,block#:49,tab#:3 found LOB$’s obj# 156 found LOB$’s dataobj#:2,ts#:0,file#:1,block#:49,tab#:6 found LOBFRAG$’s obj# 258 found LOBFRAG$’s dataobj#:258,ts#:0,file#:1,block#:3761,tab#:0 4. 获取PDATA用户下的DB_JJ_INFO_TEMP表,也就是我们要恢复的表的信息: ODU> desc PDATA.DB_JJ_INFO_TEMP Object ID:33547 Storage(Obj#=33547 DataObj#=33549 TS#=11 File#=10 Block#=1400 Cluster=0) NO. SEG INT Column Name Null? Type --- --- --- ------------------------------ --------- ------------------------------ 1 1 1 OWNER VARCHAR2(30) 2 2 2 OBJECT_NAME VARCHAR2(128) 3 3 3 SUBOBJECT_NAME VARCHAR2(30) 4 4 4 OBJECT_ID NUMBER 5 5 5 DATA_OBJECT_ID NUMBER 6 6 6 OBJECT_TYPE VARCHAR2(18) 7 7 7 CREATED DATE 8 8 8 LAST_DDL_TIME DATE 9 9 9 TIMESTAMP VARCHAR2(19) 10 10 10 STATUS VARCHAR2(7) 11 11 11 TEMPORARY VARCHAR2(1) 12 12 12 GENERATED VARCHAR2(1) 13 13 13 SECONDARY VARCHAR2(1) 从上面的输出中,我们可以看到,PDATA.DB_JJ_INFO_TEMP表所在的表空间号为11,数据段头部为10号文件的1400号块。 5. 接下来用ODU扫描表空间的extent: ODU> scan extent tablespace 11 scanning extent… scanning extent finished. 6. 我们使用ODU来确定DB_JJ_INFO_TEMP表原来的data object id。一般来说,数据段的数据块,一般是在段头后面相邻的块中。但是我们可以从段头来确认: ODU> dump datafile 10 block 1400 Block Header: block type=0×23 (ASSM segment header block) block format=0×02 (oracle 8 or 9) block rdba=0×02800578 (file#=10, block#=1400) scn=0×0000.00286f2d, seq=4, tail=0×6f2d2304 block checksum value=0×0=0, flag=0 Data Segment Header: Extent Control Header ------------------------------------------------------------- Extent Header:: extents: 1 blocks: 5 last map: 0×00000000 #maps: 0 offset: 668 Highwater:: 0×02800579 (rfile#=10,block#=1401) ext#: 0 blk#: 3 ext size:5 #blocks in seg. hdr’s freelists: 0 #blocks below: 0 mapblk: 0×00000000 offset: 0 -------------------------------------------------------- Low HighWater Mark : Highwater:: 0×02800579 ext#: 0 blk#: 3 ext size: 5 #blocks in seg. hdr’s freelists: 0 #blocks below: 0 mapblk 0×00000000 offset: 0 Level 1 BMB for High HWM block: 0×02800576 Level 1 BMB for Low HWM block: 0×02800576 -------------------------------------------------------- Segment Type: 1 nl2: 1 blksz: 2048 fbsz: 0 L2 Array start offset: 0×00000434 First Level 3 BMB: 0×00000000 L2 Hint for inserts: 0×02800577 Last Level 1 BMB: 0×02800576 Last Level 1I BMB: 0×02800577 Last Level 1II BMB: 0×00000000 Map Header:: next 0×00000000 #extents: 1 obj#: 33549 flag: 0×220000000 Extent Map ------------------------------------------------------------- 0×02800576 length: 5 Auxillary Map ------------------------------------------------------------- Extent 0 : L1 dba: 0×02800576 Data dba: 0×02800579 ------------------------------------------------------------- Second Level Bitmap block DBAs ------------------------------------------------------------- DBA 1: 0×02800577 从上面的输出中的“Extent 0 : L1 dba: 0×02800576 Data dba: 0×02800579”可以看到,段的第1个数据块的RDBA为0×02800579,也就是10号文件的1401块。 我们dump第10号文件的1401块头,来得到表DB_JJ_INFO_TEMP原来的data object id: ODU> dump datafile 10 block 1401 header Block Header: block type=0×06 (table/index/cluster segment data block) block format=0×02 (oracle 8 or 9) block rdba=0×02800579 (file#=10, block#=1401) scn=0×0000.00285f2b, seq=2, tail=0×5f2b0602 block checksum value=0×0=0, flag=0 Data Block Header Dump: Object id on Block? Y seg/obj: 0×830b=33547 csc: 0×00.285f21 itc: 3 flg: E typ: 1 (data) brn: 0 bdba: 0×2800576 ver: 0×01 Itl Xid Uba Flag Lck Scn/Fsc 0×01 0xffff.000.00000000 0×00000000.0000.00 C--- 0 scn 0×0000.00285f21 0×02 0×0000.000.00000000 0×00000000.0000.00 ---- 0 fsc 0×0000.00000000 0×03 0×0000.000.00000000 0×00000000.0000.00 ---- 0 fsc 0×0000.00000000 Data Block Dump: ================ flag=0×0 -------- ntab=1 nrow=16 frre=-1 fsbo=0×32 ffeo=0×145 avsp=0×113 tosp=0×113 可以看到,DB_JJ_INFO_TEMP表原来的data object id就是33547。 7. 使用ODU来unload数据: ODU> unload table PDATA.DB_JJ_INFO_TEMP object 33547 Unloading table: DB_JJ_INFO_TEMP,object ID: 33547 Unloading segment,storage(Obj#=33547 DataObj#=33547 TS#=11 File#=10 Block#=1400 Cluster=0) 8. 使用sqlplus将PDATA表空间ONLINE: SQL> alter tablespace test online; 表空间已更改。 9. 使用sqlldr导入我们恢复的数据: E:\ODU\data>sqlldr test/test control=TEST_T1.ctl SQL*Loader: Release 9.2.0.8.0 - Production on 星期日 3月 15 15:13:56 2009 Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved. 达到提交点,逻辑记录计数6502 达到提交点,逻辑记录计数13004 达到提交点,逻辑记录计数19506 达到提交点,逻辑记录计数26008 达到提交点,逻辑记录计数30071 至此,恢复数据的步骤已经完成。我们来对比一下数据,看看数据是否和被Truncate前的数据完全一样: SQL> select * from t2 minus select * from DB_JJ_INFO_TEMP; 可以看到,数据已经完全恢复

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值