当前位置:   article > 正文

[20190130]删除tab$记录的恢复.txt_91p.vido.ws/index.php的新网址

91p.vido.ws/index.php的新网址


--//春节前几天做了删除tan$记录的测试,链接:
[20190130]删除tab$记录的恢复.txt_ITPUB博客/=> [20190130]删除tab$记录的恢复.txt
http://blog.itpub.net/267265/viewspace-2565250/=> [20190130]删除tab$记录的恢复2.txt

--//我这样恢复后,仅仅能读,不能建表等操作,必须解决bbed verify报6110,6111,6112之类的错误问题.链接:
[20190212]删除tab$记录的恢复3.txt_ITPUB博客/=> [20190212]删除tab$记录的恢复3.txt

--//当时这些恢复,我tab$的索引i_tab1是禁用的.今天尝试恢复索引看看.

[20190225]删除tab$记录的恢复5.txt_ITPUB博客
--//做了这个测试:链接[20190226]测试使用bbed恢复索引.txt - lfree - 博客园

删除tab$记录的恢复.txt


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

--//首先我并不知道许多人的恢复方法,仅仅简单提到恢复数据字典,我想到既然是删除,反向的操作就是恢复.也就是恢复tab$记录.
--//在我开始尝试时,我发现遇到的问题比原来想像的要复杂.tab$是CLUSTER C_OBJ#的一个表.本身cluster table的结果就与普通
--//堆表的结构不一样,还有可能遇到行链接和行迁移的情况.
--//这也是我最近许多帖子关于cluster table等方面的内容.
--//自己也尝试恢复看看.

1.环境:

  1. SCOTT@book> @ ver1
  2. PORT_STRING VERSION BANNER
  3. ------------------------------ -------------- --------------------------------------------------------------------------------
  4. x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
  5. SCOTT@book>column SQL_TEXT format a100
  6. SCOTT@book> select * from (select * from SYS.BOOTSTRAP$ order by line#) where rownum<=5;
  7. LINE# OBJ# SQL_TEXT
  8. ---------- ---------- ----------------------------------------------------------------------------------------------------
  9. -1 -1 8.0.0.0.0
  10. 0 0 CREATE ROLLBACK SEGMENT SYSTEM STORAGE ( INITIAL 112K NEXT 56K MINEXTENTS 1 MAXEXTENTS 32765 OBJNO
  11. 0 EXTENTS (FILE 1 BLOCK 128))
  12. 2 2 CREATE CLUSTER C_OBJ#("OBJ#" NUMBER) PCTFREE 5 PCTUSED 40 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL
  13. 136K NEXT 200K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 2 EXTENTS (FILE 1 BLOCK 144))
  14. SIZE 800
  15. 3 3 CREATE INDEX I_OBJ# ON CLUSTER C_OBJ# PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE ( INITIAL 64K NEXT
  16. 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 3 EXTENTS (FILE 1 BLOCK 168))
  17. 4 4 CREATE TABLE TAB$("OBJ#" NUMBER NOT NULL,"DATAOBJ#" NUMBER,"TS#" NUMBER NOT NULL,"FILE#" NUMBER NOT
  18. NULL,"BLOCK#" NUMBER NOT NULL,"BOBJ#" NUMBER,"TAB#" NUMBER,"COLS" NUMBER NOT NULL,"CLUCOLS" NUMBER,"
  19. PCTFREE$" NUMBER NOT NULL,"PCTUSED$" NUMBER NOT NULL,"INITRANS" NUMBER NOT NULL,"MAXTRANS" NUMBER NO
  20. T NULL,"FLAGS" NUMBER NOT NULL,"AUDIT$" VARCHAR2(38) NOT NULL,"ROWCNT" NUMBER,"BLKCNT" NUMBER,"EMPCN
  21. T" NUMBER,"AVGSPC" NUMBER,"CHNCNT" NUMBER,"AVGRLN" NUMBER,"AVGSPC_FLB" NUMBER,"FLBCNT" NUMBER,"ANALY
  22. ZETIME" DATE,"SAMPLESIZE" NUMBER,"DEGREE" NUMBER,"INSTANCES" NUMBER,"INTCOLS" NUMBER NOT NULL,"KERNE
  23. LCOLS" NUMBER NOT NULL,"PROPERTY" NUMBER NOT NULL,"TRIGFLAG" NUMBER,"SPARE1" NUMBER,"SPARE2" NUMBER,
  24. "SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) STORAGE ( OBJNO 4 TA
  25. BNO 1) CLUSTER C_OBJ#(OBJ#)
  26. --//sys.tab$表是cluster table C_OBJ#下的一个表.OBJ#=2
  27. SELECT ROWNUM -1 rn , a.*
  28. FROM ( SELECT *
  29. FROM dba_objects
  30. WHERE owner = 'SYS' AND data_object_id = 2
  31. ORDER BY object_id) a;
  32. RN OWNER OBJECT_NAME SUBOBJECT_ OBJECT_ID DATA_OBJECT_ID OBJECT_TYPE CREATED LAST_DDL_TIME TIMESTAMP STATUS T G S NAMESPACE EDITION_NAME
  33. -- ----- ----------- ---------- --------- -------------- ----------- ------------------- ------------------- ------------------- ------- - - - ---------- ------------
  34. 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
  35. 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
  36. 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
  37. 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
  38. 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
  39. 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
  40. 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
  41. 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
  42. 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
  43. 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
  44. 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
  45. 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
  46. 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
  47. 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
  48. 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
  49. 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
  50. 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
  51. 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
  52. 18 rows selected.
  53. --//可以发现tab$仅仅是cluster table中的1个.而是是第1个表(从0算起,0是cluster table)

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

--//如何修复呢?
--//CLUSTER C_OBJ#的段头在dba 1,144.

  1. SCOTT@book> select * from dba_extents where owner='SYS' and segment_name='C_OBJ#';
  2. OWNER SEGMENT_NAME SEGMENT_TYPE TABLESPACE_NAME EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS RELATIVE_FNO
  3. ----- ------------ ------------ --------------- --------- ------- -------- ------- ------ ------------
  4. SYS C_OBJ# CLUSTER SYSTEM 0 1 144 65536 8 1
  5. SYS C_OBJ# CLUSTER SYSTEM 1 1 152 65536 8 1
  6. SYS C_OBJ# CLUSTER SYSTEM 2 1 160 65536 8 1
  7. SYS C_OBJ# CLUSTER SYSTEM 3 1 3336 65536 8 1
  8. SYS C_OBJ# CLUSTER SYSTEM 4 1 4392 65536 8 1
  9. SYS C_OBJ# CLUSTER SYSTEM 5 1 5424 65536 8 1
  10. SYS C_OBJ# CLUSTER SYSTEM 6 1 6152 65536 8 1
  11. SYS C_OBJ# CLUSTER SYSTEM 7 1 7264 65536 8 1
  12. SYS C_OBJ# CLUSTER SYSTEM 8 1 7912 65536 8 1
  13. SYS C_OBJ# CLUSTER SYSTEM 9 1 8464 65536 8 1
  14. SYS C_OBJ# CLUSTER SYSTEM 10 1 8496 65536 8 1
  15. SYS C_OBJ# CLUSTER SYSTEM 11 1 8520 65536 8 1
  16. SYS C_OBJ# CLUSTER SYSTEM 12 1 8552 65536 8 1
  17. SYS C_OBJ# CLUSTER SYSTEM 13 1 8560 65536 8 1
  18. SYS C_OBJ# CLUSTER SYSTEM 14 1 8600 65536 8 1
  19. SYS C_OBJ# CLUSTER SYSTEM 15 1 8624 65536 8 1
  20. SYS C_OBJ# CLUSTER SYSTEM 16 1 8704 1048576 128 1
  21. SYS C_OBJ# CLUSTER SYSTEM 17 1 9856 1048576 128 1
  22. SYS C_OBJ# CLUSTER SYSTEM 18 1 13312 1048576 128 1
  23. SYS C_OBJ# CLUSTER SYSTEM 19 1 17792 1048576 128 1
  24. SYS C_OBJ# CLUSTER SYSTEM 20 1 22400 1048576 128 1
  25. SYS C_OBJ# CLUSTER SYSTEM 21 1 31488 1048576 128 1
  26. SYS C_OBJ# CLUSTER SYSTEM 22 1 65920 1048576 128 1
  27. SYS C_OBJ# CLUSTER SYSTEM 23 1 73984 1048576 128 1
  28. SYS C_OBJ# CLUSTER SYSTEM 24 1 77824 1048576 128 1
  29. SYS C_OBJ# CLUSTER SYSTEM 25 1 86016 1048576 128 1
  30. SYS C_OBJ# CLUSTER SYSTEM 26 1 94208 1048576 128 1
  31. 27 rows selected.

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

  1. BBED> p /d dba 1,144 ktetb
  2. struct ktetb[0], 8 bytes @108
  3. ub4 ktetbdba @108 4194449
  4. ub4 ktetbnbk @112 7

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

  1. struct ktetb[1], 8 bytes @116
  2. ub4 ktetbdba @116 4194456
  3. ub4 ktetbnbk @120 8
  4. struct ktetb[2], 8 bytes @124
  5. ub4 ktetbdba @124 4194464
  6. ub4 ktetbnbk @128 8
  7. struct ktetb[3], 8 bytes @132
  8. ub4 ktetbdba @132 4197640
  9. ub4 ktetbnbk @136 8
  10. struct ktetb[4], 8 bytes @140
  11. ub4 ktetbdba @140 4198696
  12. ub4 ktetbnbk @144 8
  13. ..
  14. struct ktetb[25], 8 bytes @308
  15. ub4 ktetbdba @308 4280320
  16. ub4 ktetbnbk @312 128
  17. struct ktetb[26], 8 bytes @316
  18. ub4 ktetbdba @316 4288512
  19. ub4 ktetbnbk @320 128

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

  1. $ alias zdate='date +'\''%Y/%m/%d %T'\'''
  2. $ export RLWRAP=$(which rlwrap)
  3. $ type rlbbed
  4. rlbbed is a function
  5. rlbbed ()
  6. {
  7. cd /home/oracle/bbed;
  8. $RLWRAP -s 9999 -c -r -i -f /usr/local/share/rlwrap/bbed $ORACLE_HOME/bin/bbed parfile=bbed.par cmdfile=cmd.par
  9. }

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

  1. $ cat cmd.par
  2. set count 64
  3. set width 160
  4. $ cat bbed.par
  5. blocksize=8192
  6. listfile=$HOME/bbed/filelist.txt
  7. mode=edit
  8. PASSWORD=blockedit
  9. SPOOL=Y


--//filelist.txt文件通过select file#||' '||name c100 from v$dbfile order by file#;生成.
--//首先确定扫描那些块的脚本.

  1. /bin/rm /home/oracle/zzz430/bbed/scan*.txt
  2. cd /home/oracle/zzz430/bbed
  3. echo "process 1 start : `zdate` scan dba 1,144 , create scan1.txt about ktetbdba,ktetbnbk"
  4. echo "p /d dba 1,144" ktetb | rlbbed | egrep 'ktetbdba|ktetbnbk' | cut -c8-16,55- |tr " " "=" | paste -d ";" - - > scan1a.txt
  5. high_water=`echo p /d dba 1,144 ktech.hwmark_ktech.blkno_ktehw | rlbbed | grep blkno_ktehw | cut -c60- | tr -d " " `
  6. sed "\$s/ktetbnbk=.*$/ktetbnbk=$high_water/" scan1a.txt > scan1.txt
  7. read -p "process 1 finish: `zdate`,enter continue..."

--//结果保存scan1.txt
--//也就是从dba=4194449开始,扫描7块. 从4194456开始,扫描8块....如此到结束。
--//注意仅仅扫描到高水位下的块.

3.分析扫描块的情况:

  1. BBED> set dba 4194449
  2. DBA 0x00400091 (4194449 1,145)
  3. BBED> p /d kdbt[1]
  4. struct kdbt[1], 4 bytes @110
  5. sb2 kdbtoffs @110 8
  6. sb2 kdbtnrow @112 7

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

  1. BBED> x /rnnnnnnnnnnnnncnnnnnnnntnnnnnnnnnncct *kdbr[8]
  2. rowdata[7430] @7884
  3. -------------
  4. flag@7884: 0x6c (KDRHFL, KDRHFF, KDRHFH, KDRHFC)
  5. lock@7885: 0x00
  6. cols@7886: 31
  7. col 0[2] @7888: 2
  8. col 1[1] @7891: 0
  9. col 2[2] @7893: 1
  10. col 3[3] @7896: 144
  11. col 4[2] @7900: 2
  12. col 5[2] @7903: 4
  13. col 6[2] @7906: 14
  14. col 7[2] @7909: 1
  15. col 8[1] @7912: 0
  16. col 9[1] @7914: 0
  17. col 10[1] @7916: 0
  18. col 11[1] @7918: 0
  19. col 12[3] @7920: 529
  20. col 13[38] @7924: --------------------------------------
  21. col 14[3] @7963: 7789
  22. col 15[3] @7967: 1442
  23. col 16[1] @7971: 0
  24. col 17[1] @7973: 0
  25. col 18[1] @7975: 0
  26. col 19[2] @7977: 32
  27. col 20[1] @7980: 0
  28. col 21[1] @7982: 0
  29. col 22[7] @7984: 2017-02-03 22:00:18
  30. col 23[3] @7992: 7789
  31. col 24[0] @7996: *NULL*
  32. col 25[0] @7997: *NULL*
  33. col 26[2] @7998: 14
  34. col 27[2] @8001: 14
  35. col 28[3] @8004: 1024
  36. col 29[1] @8008: 0
  37. col 30[1] @8010: 0
  38. ..
  1. BBED> x /rnnnnnnnnnnnnncnnnnnnnntnnnnnnnnnncct *kdbr[14]
  2. rowdata[6684] @7138
  3. -------------
  4. flag@7138: 0x6c (KDRHFL, KDRHFF, KDRHFH, KDRHFC)
  5. lock@7139: 0x02
  6. cols@7140: 31
  7. ckix@7141: 7
  8. col 0[2] @7142: 2
  9. col 1[1] @7145: 0
  10. col 2[2] @7147: 1
  11. col 3[3] @7150: 144
  12. col 4[2] @7154: 2
  13. col 5[2] @7157: 3
  14. col 6[2] @7160: 34
  15. col 7[2] @7163: 1
  16. col 8[1] @7166: 0
  17. col 9[1] @7168: 0
  18. col 10[1] @7170: 0
  19. col 11[1] @7172: 0
  20. col 12[3] @7174: 529
  21. col 13[38] @7178: --------------------------------------
  22. col 14[3] @7217: 5066
  23. col 15[3] @7221: 1442
  24. col 16[1] @7225: 0
  25. col 17[1] @7227: 0
  26. col 18[1] @7229: 0
  27. col 19[2] @7231: 91
  28. col 20[1] @7234: 0
  29. col 21[1] @7236: 0
  30. col 22[7] @7238: 2017-02-22 22:00:13
  31. col 23[3] @7246: 5066
  32. col 24[0] @7250: *NULL*
  33. col 25[0] @7251: *NULL*
  34. col 26[2] @7252: 34
  35. col 27[2] @7255: 34
  36. col 28[3] @7258: 1024
  37. col 29[1] @7262: 0
  38. col 30[1] @7264: 0

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

  1. echo "process 2 start : `zdate` scan block , get kdbtnrow,kdbtoffs ang grep kdbtnrow=0"
  2. cat scan1.txt | while read i
  3. do
  4. eval $i
  5. #echo $ktetbdba $ktetbnbk
  6. for ((j=1; j<=$ktetbnbk ; j++))
  7. do
  8. echo -n "dba=$ktetbdba;" >> scan2a.txt
  9. echo "p /d dba $ktetbdba offset 0 kdbt[1]" | rlbbed | egrep 'kdbtoffs|kdbtnrow' | cut -c8-16,55- |tr " " "=" | paste -d ";" - - >> scan2a.txt
  10. ktetbdba=$[ ktetbdba + 1 ]
  11. #echo $ktetbdba
  12. done
  13. done
  14. grep -v kdbtnrow=0 scan2a.txt > scan2.txt
  15. read -p "process 2 finish: `zdate`,enter continue..."
  16. ..

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

  1. $ head scan2.txt
  2. dba=4194449;kdbtoffs=8;kdbtnrow=7
  3. dba=4194450;kdbtoffs=8;kdbtnrow=5
  4. dba=4194451;kdbtoffs=9;kdbtnrow=6
  5. dba=4194452;kdbtoffs=10;kdbtnrow=9
  6. dba=4194453;kdbtoffs=10;kdbtnrow=10
  7. dba=4194454;kdbtoffs=10;kdbtnrow=10
  8. dba=4194455;kdbtoffs=10;kdbtnrow=10
  9. dba=4194456;kdbtoffs=10;kdbtnrow=10
  10. dba=4194457;kdbtoffs=10;kdbtnrow=10
  11. dba=4194458;kdbtoffs=7;kdbtnrow=7

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

  1. 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 "
  2. cat scan2.txt | while read i
  3. do
  4. eval $i
  5. begin=$kdbtoffs
  6. end=$[ kdbtoffs + kdbtnrow -1 ]
  7. # echo $dba $kdbtoffs $kdbtnrow $begin $end
  8. kdbr_size=`echo map dba $dba| rlbbed | grep "sb2 kdbr" | sed -e "s/^.*\[//" -e "s/].*$//" `
  9. while [ $begin -le $end ]
  10. do
  11. kdbr_off=`echo p dba $dba offset 0 kdbr | rlbbed | grep "\[$begin\]" | cut -c55-`
  12. if [ $kdbr_off -gt $kdbr_size ]
  13. then
  14. 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
  15. #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
  16. do
  17. eval $k
  18. #echo $dba $offset $value
  19. value=`printf "0x%x" $(( value - 0x10 )) `
  20. echo "assign /x dba $dba offset $offset = $value " >> scan3_bbed.txt
  21. done
  22. # if not found ckix@ and found flag=0x7c , then ckix_value=0, and do not process chained row.
  23. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | grep "^ckix@" | sed -e "s/^ckix/dba=$dba;/" -e 's/@.*:/ckix_value=/' | tr -d " " >> scan4a.txt
  24. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^ckix@" > /dev/null
  25. if [ $? -eq 1 ]
  26. then
  27. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^^flag@.*: *0x7c" > /dev/null
  28. if [ $? -eq 0 ]
  29. then
  30. echo "dba=$dba;ckix_value=0" >> scan4a.txt
  31. fi
  32. fi
  33. fi
  34. begin=$[ begin + 1 ]
  35. done
  36. done
  37. 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替代,如果存在行迁移,跳过不处理.

  1. assign /x dba 4194449 offset 7884 = 0x5c
  2. assign /x dba 4194449 offset 7756 = 0x5c
  3. assign /x dba 4194449 offset 7632 = 0x5c
  4. assign /x dba 4194449 offset 7512 = 0x5c
  5. assign /x dba 4194449 offset 7388 = 0x5c
  6. assign /x dba 4194449 offset 7266 = 0x5c
  7. assign /x dba 4194449 offset 7138 = 0x5c
  8. assign /x dba 4194450 offset 509 = 0x5c
  9. assign /x dba 4194450 offset 7882 = 0x5c
  10. assign /x dba 4194450 offset 7756 = 0x5c

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

  1. $ head scan4a.txt
  2. dba=4194449;ckix_value=0
  3. dba=4194449;ckix_value=1
  4. dba=4194449;ckix_value=2
  5. dba=4194449;ckix_value=4
  6. dba=4194449;ckix_value=5
  7. dba=4194449;ckix_value=6
  8. dba=4194449;ckix_value=7
  9. dba=4194450;ckix_value=1
  10. dba=4194450;ckix_value=3
  11. dba=4194450;ckix_value=4

4.修改mref_offset标识:

  1. echo "process 4 start : `zdate` create bbed's scan4_bbed.txt for modify cluster of mref of value "
  2. sort scan4a.txt | uniq > scan4b.txt
  3. cat scan4b.txt | while read i
  4. do
  5. eval $i
  6. #echo $dba $ckix_value
  7. echo -n "dba=$dba;" >> scan4c.txt
  8. 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
  9. done
  10. sed -e 's/;$/;mref_offset=0;value=0/' -e 's/value=/valuek=/' scan4c.txt > scan4.txt
  11. cat scan4.txt | while read i
  12. do
  13. eval $i
  14. # echo $dba $kref_offset $valuek $mref_offset $value
  15. if [ $mref_offset -eq 0 ]
  16. then
  17. mref_offset=$[ $kref_offset+ 2 ]
  18. fi
  19. valuem=$[ value + 1 ]
  20. if [ $valuem -lt $valuek ]
  21. then
  22. echo "assign dba $dba offset $mref_offset = $valuem" >> scan4m_bbed.txt
  23. else
  24. echo "assign dba $dba offset $mref_offset = $valuek" >> scan4k_bbed.txt
  25. fi
  26. done
  27. 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脚本:

  1. echo "process 5 start : create bbed's scan5_bbed.txt for sum apply"
  2. sed -e 's/^dba=/sum apply dba /' -e 's/;.*$//' scan2.txt > scan5_bbed.txt
  3. read -p "process 5 finish: `zdate`,enter continue..."

6.注意问题.

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

  1. SYS@book> select rowid,a.* from SYS.BOOTSTRAP$ a where a.sql_text like '%I_TAB1%';
  2. ROWID LINE# OBJ# SQL_TEXT
  3. ------------------ ---------- ---------- ------------------------------------------------------------
  4. AAAAA7AABAAAAILAAJ 33 33 CREATE INDEX I_TAB1 ON TAB$(BOBJ#) PCTFREE 10 INITRANS 2 MAX
  5. TRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAX
  6. EXTENTS 2147483645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BL
  7. OCK 312))

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

  1. SYS@book> @ rowid AAAAA7AABAAAAILAAJ
  2. OBJECT FILE BLOCK ROW ROWID_DBA DBA TEXT
  3. ---------- ---------- ---------- ---------- -------------------- -------------------- ----------------------------------------
  4. 59 1 523 9 0x40020B 1,523 alter system dump datafile 1 block 523 ;
  5. BBED> x /rnnc dba 1,523 *kdbr[9]
  6. rowdata[1269] @4910
  7. -------------
  8. flag@4910: 0x2c (KDRHFL, KDRHFF, KDRHFH)
  9. lock@4911: 0x01
  10. cols@4912: 3
  11. col 0[2] @4913: 33
  12. col 1[2] @4916: 33
  13. 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
  14. 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启动数据库.可能还有一些
--//细节需要注意.

[20190130]删除tab$记录的恢复2.txt


--//前面链接写好了脚本,开始测试删除后的恢复.千万不要在生产系统做这样的测试!!
--//参考链接:http://blog.itpub.net/267265/viewspace-2565245/=>[20190130]删除tab$记录的恢复.txt

1.环境:

  1. SCOTT@book> @ ver1
  2. PORT_STRING VERSION BANNER
  3. ------------------------------ -------------- --------------------------------------------------------------------------------
  4. x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
  5. create table ORACHK001 tablespace system as select * from sys.tab$;
  6. SYS@book> create table ORACHK001 tablespace system as select * from sys.tab$;
  7. Table created.
  8. SYS@book> select count(*) from sys.tab$;
  9. COUNT(*)
  10. ----------
  11. 2966
  12. SYS@book> select count(*) from orachk001;
  13. COUNT(*)
  14. ----------
  15. 2965

--//这样建立的表不包含orachk001.

  1. SYS@book> select * from sys.tab$ minus select * from orachk001;
  2. ...
  3. SYS@book> select OBJ# , DATAOBJ# from sys.tab$ minus select OBJ# , DATAOBJ# from orachk001;
  4. OBJ# DATAOBJ#
  5. ---------- ----------
  6. 91090 91090
  7. SYS@book> insert into orachk001 select * from sys.tab$ where (OBJ#,DATAOBJ#) in ((91090,91090));
  8. 1 row created.
  9. SYS@book> commit ;
  10. Commit complete.

2.做一个冷备份:
--//关闭数据库略.

$ cp -r /mnt/ramdisk/book /home/oracle/backup/


--//重启数据库.

  1. SYS@book> startup
  2. ORACLE instance started.
  3. Total System Global Area 643084288 bytes
  4. Fixed Size 2255872 bytes
  5. Variable Size 205521920 bytes
  6. Database Buffers 427819008 bytes
  7. Redo Buffers 7487488 bytes
  8. Database mounted.
  9. Database opened.
  10. SYS@book> delete from sys.tab$;
  11. 2966 rows deleted.
  12. SYS@book> commit ;
  13. Commit complete.
  14. SYS@book> alter system checkpoint ;
  15. System altered.
  16. SYS@book> alter system checkpoint ;
  17. System altered.
  18. SYS@book> alter system checkpoint ;
  19. System altered.
  20. SYS@book> shutdown immediate ;
  21. ORA-00957: duplicate column name
  22. SYS@book> shutdown abort ;
  23. ORACLE instance shut down.


--//再保留一份坏的备份.
 

  1. $ mv /home/oracle/backup/book /home/oracle/backup/book_20190122_good
  2. `/home/oracle/backup/book' -> `/home/oracle/backup/book_20190122_good'
  3. $ cp -r /mnt/ramdisk/book /home/oracle/backup/
  4. $ mv /home/oracle/backup/book /home/oracle/backup/book_20190122_bad
  5. `/home/oracle/backup/book' -> `/home/oracle/backup/book_20190122_bad'



3.开始恢复:


--//执行如下脚本,自己建立目录/home/oracle/zzz430,zdate,rlbbed是别名.看前面的链接.
--//脚本scan.sh:

  1. #! /bin/bash
  2. /bin/rm /home/oracle/zzz430/bbed/scan*.txt
  3. cd /home/oracle/zzz430/bbed
  4. echo "process 1 start : `zdate` scan dba 1,144 , create scan1.txt about ktetbdba,ktetbnbk"
  5. echo "p /d dba 1,144" ktetb | rlbbed | egrep 'ktetbdba|ktetbnbk' | cut -c8-16,55- |tr " " "=" | paste -d ";" - - > scan1a.txt
  6. high_water=`echo p /d dba 1,144 ktech.hwmark_ktech.blkno_ktehw | rlbbed | grep blkno_ktehw | cut -c60- | tr -d " " `
  7. sed "\$s/ktetbnbk=.*$/ktetbnbk=$high_water/" scan1a.txt > scan1.txt
  8. read -p "process 1 finish: `zdate`,enter continue..."
  9. echo "process 2 start : `zdate` scan block , get kdbtnrow,kdbtoffs ang grep kdbtnrow=0"
  10. cat scan1.txt | while read i
  11. do
  12. eval $i
  13. #echo $ktetbdba $ktetbnbk
  14. for ((j=1; j<=$ktetbnbk ; j++))
  15. do
  16. echo -n "dba=$ktetbdba;" >> scan2a.txt
  17. echo "p /d dba $ktetbdba offset 0 kdbt[1]" | rlbbed | egrep 'kdbtoffs|kdbtnrow' | cut -c8-16,55- |tr " " "=" | paste -d ";" - - >> scan2a.txt
  18. ktetbdba=$[ ktetbdba + 1 ]
  19. #echo $ktetbdba
  20. done
  21. done
  22. grep -v kdbtnrow=0 scan2a.txt > scan2.txt
  23. read -p "process 2 finish: `zdate`,enter continue..."
  24. 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 "
  25. cat scan2.txt | while read i
  26. do
  27. eval $i
  28. begin=$kdbtoffs
  29. end=$[ kdbtoffs + kdbtnrow -1 ]
  30. # echo $dba $kdbtoffs $kdbtnrow $begin $end
  31. kdbr_size=`echo map dba $dba| rlbbed | grep "sb2 kdbr" | sed -e "s/^.*\[//" -e "s/].*$//" `
  32. while [ $begin -le $end ]
  33. do
  34. kdbr_off=`echo p dba $dba offset 0 kdbr | rlbbed | grep "\[$begin\]" | cut -c55-`
  35. if [ $kdbr_off -gt $kdbr_size ]
  36. then
  37. 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
  38. #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
  39. do
  40. eval $k
  41. #echo $dba $offset $value
  42. value=`printf "0x%x" $(( value - 0x10 )) `
  43. echo "assign /x dba $dba offset $offset = $value " >> scan3_bbed.txt
  44. done
  45. # if not found ckix@ and found flag=0x7c , then ckix_value=0, and do not process chained row.
  46. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | grep "^ckix@" | sed -e "s/^ckix/dba=$dba;/" -e 's/@.*:/ckix_value=/' | tr -d " " >> scan4a.txt
  47. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^ckix@" > /dev/null
  48. if [ $? -eq 1 ]
  49. then
  50. echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^^flag@.*: *0x7c" > /dev/null
  51. if [ $? -eq 0 ]
  52. then
  53. echo "dba=$dba;ckix_value=0" >> scan4a.txt
  54. fi
  55. fi
  56. fi
  57. begin=$[ begin + 1 ]
  58. done
  59. done
  60. read -p "process 3 finish: `zdate`,enter continue..."
  61. echo "process 4 start : `zdate` create bbed's scan4_bbed.txt for modify cluster of mref of value "
  62. sort scan4a.txt | uniq > scan4b.txt
  63. cat scan4b.txt | while read i
  64. do
  65. eval $i
  66. #echo $dba $ckix_value
  67. echo -n "dba=$dba;" >> scan4c.txt
  68. 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
  69. done
  70. sed -e 's/;$/;mref_offset=0;value=0/' -e 's/value=/valuek=/' scan4c.txt > scan4.txt
  71. cat scan4.txt | while read i
  72. do
  73. eval $i
  74. # echo $dba $kref_offset $valuek $mref_offset $value
  75. if [ $mref_offset -eq 0 ]
  76. then
  77. mref_offset=$[ $kref_offset+ 2 ]
  78. fi
  79. valuem=$[ value + 1 ]
  80. if [ $valuem -lt $valuek ]
  81. then
  82. echo "assign dba $dba offset $mref_offset = $valuem" >> scan4m_bbed.txt
  83. else
  84. echo "assign dba $dba offset $mref_offset = $valuek" >> scan4k_bbed.txt
  85. fi
  86. done
  87. read -p "process 4 finish: `zdate`,enter continue..."
  88. echo "process 5 start : create bbed's scan5_bbed.txt for sum apply"
  89. sed -e 's/^dba=/sum apply dba /' -e 's/;.*$//' scan2.txt > scan5_bbed.txt
  90. read -p "process 5 finish: `zdate`,enter continue..."


--//执行脚本scan.sh.

  1. $ . scan.sh
  2. process 1 start : 2019/01/30 10:20:32 scan dba 1,144 , create scan1.txt about ktetbdba,ktetbnbk
  3. process 1 finish: 2019/01/30 10:20:33,enter continue...
  4. process 2 start : 2019/01/30 10:20:33 scan block , get kdbtnrow,kdbtoffs ang grep kdbtnrow=0
  5. process 2 finish: 2019/01/30 10:21:04,enter continue...
  6. process 3 start : 2019/01/30 10:21:28 scan block , create bbed'script scan3_bbed.txt for modify delete of flag and create scan4a.txt about block of ckix
  7. process 3 finish: 2019/01/30 10:26:36,enter continue...
  8. process 4 start : 2019/01/30 10:26:42 create bbed's scan4_bbed.txt for modify cluster of mref of value
  9. process 4 finish: 2019/01/30 10:27:47,enter continue...
  10. process 5 start : create bbed's scan5_bbed.txt for sum apply
  11. process 5 finish: 2019/01/30 10:27:52,enter continue...


--//主要时间消耗在第3步,大约需要5分多钟.看看生成修改的脚本:
 

  1. $ ls -l scan*bbed*
  2. -rw-r--r-- 1 oracle oinstall 124731 2019-01-30 10:26:36 scan3_bbed.txt
  3. -rw-r--r-- 1 oracle oinstall 105556 2019-01-30 10:27:47 scan4k_bbed.txt
  4. -rw-r--r-- 1 oracle oinstall 70 2019-01-30 10:27:47 scan4m_bbed.txt
  5. -rw-r--r-- 1 oracle oinstall 12782 2019-01-30 10:27:52 scan5_bbed.txt
  6. $ head scan3_bbed.txt
  7. assign /x dba 4194449 offset 7884 = 0x6c
  8. assign /x dba 4194449 offset 7756 = 0x6c
  9. assign /x dba 4194449 offset 7632 = 0x6c
  10. assign /x dba 4194449 offset 7512 = 0x6c
  11. assign /x dba 4194449 offset 7388 = 0x6c
  12. assign /x dba 4194449 offset 7266 = 0x6c
  13. assign /x dba 4194449 offset 7138 = 0x6c
  14. assign /x dba 4194450 offset 509 = 0x6c
  15. assign /x dba 4194450 offset 7882 = 0x6c
  16. assign /x dba 4194450 offset 7756 = 0x6c
  17. $ head scan4k_bbed.txt
  18. assign dba 4194449 offset 8171 = 17
  19. assign dba 4194449 offset 8149 = 15
  20. assign dba 4194449 offset 8127 = 27
  21. assign dba 4194449 offset 8083 = 11
  22. assign dba 4194449 offset 8061 = 20
  23. assign dba 4194449 offset 8039 = 8
  24. assign dba 4194449 offset 8017 = 34
  25. assign dba 4194450 offset 8149 = 21
  26. assign dba 4194450 offset 8105 = 34
  27. assign dba 4194450 offset 8083 = 27
  28. $ head scan4m_bbed.txt
  29. assign dba 4288539 offset 8169 = 1
  30. assign dba 4288546 offset 8145 = 1
  31. $ head scan5_bbed.txt
  32. sum apply dba 4194449
  33. sum apply dba 4194450
  34. sum apply dba 4194451
  35. sum apply dba 4194452
  36. sum apply dba 4194453
  37. sum apply dba 4194454
  38. sum apply dba 4194455
  39. sum apply dba 4194456
  40. sum apply dba 4194457
  41. sum apply dba 4194458


--//注意检查修改flag不是0x6c的记录.

  1. $ grep -v "0x6c $" scan3_bbed.txt
  2. assign /x dba 4194451 offset 7349 = 0x20
  3. assign /x dba 4197642 offset 7888 = 0x20
  4. assign /x dba 4207636 offset 7087 = 0x20
  5. assign /x dba 4225801 offset 3621 = 0x4c
  6. assign /x dba 4225801 offset 4436 = 0x4c
  7. assign /x dba 4288537 offset 7717 = 0x4c
  8. $ grep "0x6c $" scan3_bbed.txt |wc
  9. 2965 23720 124479



--//可以发现dba=4194451发生了行迁移行,删除后一样存在标识KDRHFD.(注:101是好的system01.dbf文件)

  1. BBED> x /rx dba 4194451 *kdbr[14]
  2. rowdata[6848] @7349
  3. -------------
  4. flag@7349: 0x30 (KDRHFD, KDRHFH)
  5. lock@7350: 0x02
  6. cols@7351: 0
  7. BBED> x /rx dba 101,147 *kdbr[14]
  8. rowdata[6848] @7349
  9. -------------
  10. flag@7349: 0x20 (KDRHFH)
  11. lock@7350: 0x02
  12. cols@7351: 0
  13. nrid@7352:0x00407b09.1
  14. --//dba=4197642也是原来发生了行迁移.
  15. BBED> x /rx dba 4197642 *kdbr[8]
  16. rowdata[7431] @7888
  17. -------------
  18. flag@7888: 0x30 (KDRHFD, KDRHFH)
  19. lock@7889: 0x02
  20. cols@7890: 0
  21. BBED> x /rx dba 101,3338 *kdbr[8]
  22. rowdata[7431] @7888
  23. -------------
  24. flag@7888: 0x20 (KDRHFH)
  25. lock@7889: 0x00
  26. cols@7890: 0
  27. nrid@7891:0x00407b09.0



--//dba=4207636也是原来发生了行迁移.

  1. BBED> x /rx dba 4207636 *kdbr[16]
  2. rowdata[6599] @7087
  3. -------------
  4. flag@7087: 0x30 (KDRHFD, KDRHFH)
  5. lock@7088: 0x02
  6. cols@7089: 0
  7. BBED> x /rx dba 101,13332 *kdbr[16]
  8. rowdata[6599] @7087
  9. -------------
  10. flag@7087: 0x20 (KDRHFH)
  11. lock@7088: 0x00
  12. cols@7089: 0
  13. nrid@7090:0x00417019.2


--//分析assign /x dba 4225801 offset 3621 = 0x4c的情况.

  1. BBED> x /rx dba 4225801 *kdbr[10]
  2. rowdata[0] @3621
  3. ----------
  4. flag@3621: 0x5c (KDRHFL, KDRHFF, KDRHFD, KDRHFC)
  5. lock@3622: 0x02
  6. cols@3623: 0
  7. ckix@3624: 6
  8. BBED> x /rx dba 101,31497 *kdbr[10]
  9. rowdata[0] @3621
  10. ----------
  11. flag@3621: 0x4c (KDRHFL, KDRHFF, KDRHFC)
  12. lock@3622: 0x00
  13. cols@3623: 31
  14. ckix@3624: 6
  15. hrid@3625:0x00400d0a.1
  16. col 0[3] @3631: 0xc2 0x06 0x1b
  17. col 1[1] @3635: 0x80


--//0x400d0a=4197642,4197642= alter system dump datafile 1 block 3338,实际上行迁移的部分.
--//实际上你可以看出我多恢复了几条. 3+2965 = 2968,这样多恢复2条.

--//我写脚本扫描块,取出tailchk值,发现大部分都是0x5f5[cdef]的信息.

  1. $ cat scanx.sh
  2. #! /bin/bash
  3. grep dba scan3_bbed.txt | cut -d" " -f4 | uniq | while read dba
  4. do
  5. echo -n $dba :
  6. echo "p dba $dba offset 8188"| rlbbed | grep "ub4 tailchk"
  7. done
  8. $ . scanx.sh | cut -c64-71 | sort|uniq -c
  9. 1 0x2d3e06
  10. 69 0x5f5c06
  11. 5 0x5f5d06
  12. 499 0x5f5f06
  13. 1 0xdde306
  14. $ . scanx.sh | grep -v '0x5f5[0-9abcdef]06'
  15. 4288539 :ub4 tailchk @8188 0xdde30601
  16. 4288546 :ub4 tailchk @8188 0x2d3e0601
  17. $ egrep -n '4288539|4288546' scan3_bbed.txt
  18. 2962:#assign /x dba 4288539 offset 7920 = 0x6c
  19. 2971:#assign /x dba 4288546 offset 7851 = 0x6c


--//可以确定这两个块不需要修改,因为scn号相差太大.而且正好2条记录,估计以前删除表留下痕迹,与前面的信息正好吻合.
--//注解对应行取消它的执行.

$ cat scan4m_bbed.txt
assign dba 4288539 offset 8169 = 1
assign dba 4288546 offset 8145 = 1
--//以上脚本也许不需要执行.但是还有如下tailchk不是0x5f5f是什么回事呢?
     69 0x5f5c06
      5 0x5f5d06

--//实际上这个是延迟块块提交的产物,当dml修改块很多的情况下,仅仅部分块做快速提交(好像是缓存的某个百分比).
--//也就是有74块需要特殊处理.不然在open时报错,或者数据库直接关闭.参考链接:
--//http://blog.itpub.net/267265/viewspace-2564717/ => [20190124]bbed恢复数据遇到延迟块清除的问题2.txt
--//也就是oracle对于system表空间检测更加严格,不知道有什么参数可以临时关闭或者绕过这种检测.

4.执行生成的bbed脚本.

  1. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/zzz430/bbed/scan3_bbed.txt
  2. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/zzz430/bbed/scan4k_bbed.txt
  3. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/zzz430/bbed/scan5_bbed.txt


--//注意输入Y.
--//如果通过管道执行脚本,必须修改脚本在第2行加入Y.

5.禁用sys.tab$的索引I_TAB1.
--//这样恢复,索引与表存在不一致情况,要禁用sys.tab$的索引I_TAB1.
 

  1. BBED> x /rnnc dba 1,523 *kdbr[9]
  2. rowdata[1269] @4910
  3. -------------
  4. flag@4910: 0x2c (KDRHFL, KDRHFF, KDRHFH)
  5. lock@4911: 0x01
  6. cols@4912: 3
  7. col 0[2] @4913: 33
  8. col 1[2] @4916: 33
  9. 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
  10. 645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BLOCK 312))


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

  1. BBED> assign /x dba 1,523 offset 4910= 0x3c
  2. Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
  3. ub1 rowdata[0] @4910 0x3c
  4. BBED> sum apply dba 1,523
  5. Check value for File 1, Block 523:
  6. current = 0x7e6b, required = 0x7e6b


6.启动数据库看看:

  1. SYS@book> create pfile='/tmp/@.ora' from spfile ;
  2. File created.



--//修改/tmp/book.ora文件,加入修改如下:

  1. *._system_trig_enabled=false
  2. *.job_queue_processes=0



--//启动遇到如下错误:

  1. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [94232], [6110], [], [], [], [], [], [], [], []
  2. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [9951], [6110], [], [], [], [], [], [], [], []
  3. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [31548], [6110], [], [], [], [], [], [], [], []



--//实际上我修复dba=1,94232后出现dba=1,9951.接着修复,接着在出现1,31548.而且这块还标识为坏块.即使启动ok,错误不断,都是
--//涉及tab$的块记录.实际上就是我前面提到延迟提交的问题.

--//分析dba=1,94232

  1. BBED> set dba 1 , 94232
  2. DBA 0x00417018 (4288536 1,94232)
  3. BBED> p tailchk
  4. ub4 tailchk @8188 0x5f5d0601



--//可以这些都是延迟块提交导致对应块没有更新.

  1. BBED> p dba 1, 94232 ktbbh.ktbbhitl[1]
  2. struct ktbbhitl[1], 24 bytes @68
  3. struct ktbitxid, 8 bytes @68
  4. ub2 kxidusn @68 0x0005
  5. ub2 kxidslt @70 0x0018
  6. ub4 kxidsqn @72 0x00000751
  7. struct ktbituba, 8 bytes @76
  8. ub4 kubadba @76 0x00c0050f
  9. ub2 kubaseq @80 0x04eb
  10. ub1 kubarec @82 0x0b
  11. ub2 ktbitflg @84 0x0001 (NONE)
  12. union _ktbitun, 2 bytes @86
  13. sb2 _ktbitfsc @86 126
  14. ub2 _ktbitwrp @86 0x007e
  15. ub4 ktbitbas @88 0x00000000
  16. BBED> p dba 1, 9951 ktbbh.ktbbhitl[1]
  17. struct ktbbhitl[1], 24 bytes @68
  18. struct ktbitxid, 8 bytes @68
  19. ub2 kxidusn @68 0x0005
  20. ub2 kxidslt @70 0x0018
  21. ub4 kxidsqn @72 0x00000751
  22. struct ktbituba, 8 bytes @76
  23. ub4 kubadba @76 0x00c0013f
  24. ub2 kubaseq @80 0x04de
  25. ub1 kubarec @82 0x1b
  26. ub2 ktbitflg @84 0x0005 (NONE)
  27. union _ktbitun, 2 bytes @86
  28. sb2 _ktbitfsc @86 695
  29. ub2 _ktbitwrp @86 0x02b7
  30. ub4 ktbitbas @88 0x00000000
  31. BBED> p dba 1, 31548 ktbbh.ktbbhitl[1]
  32. struct ktbbhitl[1], 24 bytes @68
  33. struct ktbitxid, 8 bytes @68
  34. ub2 kxidusn @68 5
  35. ub2 kxidslt @70 24
  36. ub4 kxidsqn @72 1873
  37. struct ktbituba, 8 bytes @76
  38. ub4 kubadba @76 12583968
  39. ub2 kubaseq @80 1251
  40. ub1 kubarec @82 19
  41. ub2 ktbitflg @84 5 (NONE)
  42. union _ktbitun, 2 bytes @86
  43. sb2 _ktbitfsc @86 570
  44. ub2 _ktbitwrp @86 570
  45. ub4 ktbitbas @88 0
  46. BBED> p dba 1, 31548 ktbbh.ktbbhitl[1]
  47. struct ktbbhitl[1], 24 bytes @68
  48. struct ktbitxid, 8 bytes @68
  49. ub2 kxidusn @68 0x0005
  50. ub2 kxidslt @70 0x0018
  51. ub4 kxidsqn @72 0x00000751
  52. struct ktbituba, 8 bytes @76
  53. ub4 kubadba @76 0x00c00420
  54. ub2 kubaseq @80 0x04e3
  55. ub1 kubarec @82 0x13
  56. ub2 ktbitflg @84 0x0005 (NONE)
  57. union _ktbitun, 2 bytes @86
  58. sb2 _ktbitfsc @86 570
  59. ub2 _ktbitwrp @86 0x023a
  60. ub4 ktbitbas @88 0x00000000


---//注意.xid=0x0005.0x0018.0x00000751.其对应的ktbitbas是0. 其ktbitflg也可以看出没有提交.
--//我单独写一个脚本:

  1. $ cat scanx.sh
  2. #! /bin/bash
  3. grep dba scan3_bbed.txt | cut -d" " -f4 | uniq | while read dba
  4. do
  5. echo -n $dba :
  6. echo "p dba $dba offset 8188"| rlbbed | grep "ub4 tailchk"
  7. done


$ . scanx.sh | grep -v 0x5f5f06 >| clearout.txt
--//先取出taichk不是5f5f的记录.注意删除dba=4288539,4288546 两行.

  1. $ cat scana.sh
  2. #! /bin/bash
  3. cat clearout.txt | while read dba
  4. do
  5. echo set dba $dba
  6. echo -n "assign "
  7. echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$"| egrep "ktbbhitl|ktbitflg" | cut -c11-21,55-60 | paste -d. - - | sed -e 's/ /=/'
  8. echo sum apply dba $dba
  9. done


--//注:仅仅读取存在ub4 kxidsqn @72 0x00000751,不大可能别的ITL槽kxidsqn也正好是这个值.
 

  1. $ . scana.sh >| clearout_bbed.txt
  2. $ head clearout_bbed.txt
  3. set dba 4204236
  4. assign ktbbhitl[1].ktbitflg=0x0002
  5. sum apply dba 4204236
  6. set dba 4204237
  7. assign ktbbhitl[1].ktbitflg=0x0003
  8. sum apply dba 4204237
  9. set dba 4204241
  10. assign ktbbhitl[1].ktbitflg=0x0002
  11. sum apply dba 4204241
  12. set dba 4204243



--//使用vim执行:%s/=0x00/=0x20/g.也就是设置提交标识.注意检查替换是否74行.
--//不想在写脚本了.^_^.
 

  1. $ bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/zzz430/bbed/clearout_bbed.txt
  2. $ bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/zzz430/bbed/scan5_bbed.txt
  3. SYS@book> startup pfile='/tmp/book.ora'
  4. ORACLE instance started.
  5. Total System Global Area 643084288 bytes
  6. Fixed Size 2255872 bytes
  7. Variable Size 205521920 bytes
  8. Database Buffers 427819008 bytes
  9. Redo Buffers 7487488 bytes
  10. Database mounted.
  11. Database opened.
  12. SYS@book> shutdown immediate ;
  13. Database closed.
  14. Database dismounted.
  15. ORACLE instance shut down.


--//OK.马上关闭以只读打开看看.

  1. SYS@book> startup open read only pfile='/tmp/book.ora'
  2. ORACLE instance started.
  3. Total System Global Area 643084288 bytes
  4. Fixed Size 2255872 bytes
  5. Variable Size 205521920 bytes
  6. Database Buffers 427819008 bytes
  7. Redo Buffers 7487488 bytes
  8. Database mounted.
  9. Database opened.
  10. select /*+ full(tab$) */ * from tab$;


--//没有任何错误.
 

  1. SYS@book> select count(*) from tab$;
  2. COUNT(*)
  3. ----------
  4. 2966
  5. SYS@book> select /*+ full(tab$) */ count(*) from tab$;
  6. COUNT(*)
  7. ----------
  8. 2966


--//完全能与前面的对上.

  1. SYS@book> select * from sys.tab$ minus select * from orachk001;
  2. no rows selected
  3. SYS@book> select * from orachk001 minus select * from sys.tab$;
  4. no rows selected



--//几乎完美恢复.
--//一般情况下这样的数据库做好导出到另外的数据库,执行如下类似导出操作,没有任何问题.仅仅owner=oe出现如下错误:

  1. $ exp system/oracle file=a.dmp owner=oe BUFFER=8388608
  2. Export: Release 11.2.0.4.0 - Production on Wed Jan 30 11:56:02 2019
  3. Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
  4. Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
  5. With the Partitioning, OLAP, Data Mining and Real Application Testing options
  6. Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set
  7. About to export specified users ...
  8. . exporting pre-schema procedural objects and actions
  9. . exporting foreign function library names for user OE
  10. . exporting PUBLIC type synonyms
  11. . exporting private type synonyms
  12. . exporting object type definitions for user OE
  13. About to export OE's objects ...
  14. . exporting database links
  15. . exporting sequence numbers
  16. . exporting cluster definitions
  17. EXP-00056: ORACLE error 8181 encountered
  18. ORA-08181: specified number is not a valid system change number
  19. ORA-06512: at "SYS.XMLTYPE", line 138
  20. EXP-00000: Export terminated unsuccessfully


--//不过我读写模式下打开数据库没有问题,视乎执行如下:

  1. SELECT VALUE (p$)
  2. FROM "XDB"."XDB$SCHEMA" AS OF SNAPSHOT ( :2) p$
  3. WHERE SYS_NC_OID$ = :1


--//我在toad下schema模式下点击data(open read only),调用如下sql语句:

  1. SYS@book> SELECT X.SYS_NC_ROWINFO$.GetClobVal () AS SYS_NC_ROWINFO$ FROM XDB.XDB$SCHEMA X;
  2. ERROR:
  3. ORA-08181: specified number is not a valid system change number
  4. ORA-06512: at "SYS.XMLTYPE", line 138
  5. no rows selected



--//有点奇怪的是在dg下active dataguard mode下(read only),不报错.另外写一篇blog分析这个问题.


4.后记:


--//我脚本实际上元旦之前就写差不多,当然还有许多细节没有考虑好.比如行迁移或者链接问题.
--//还有bbed 如果ckix=0,mref=0不显示的问题.
--//还有就是延迟提交导致的问题,等等许多细节几乎导致我放弃恢复测试.

--//使用bash shell写脚本实际上执行效率很低的操作,通过这个恢复,了解许多oracle cluster table许多相关知识,
--//还有一些细节的处理,许多编码是使用cut硬性编码取出对于值.不能保证你遇到类似问题,直接拿来使用.^_^
--//何况真实的生产系统可能比我在测试环境遇到的问题更加复杂.

[20190212]删除tab$记录的恢复3.txt

--//春节前几天做了删除tan$记录的测试,链接:
http://blog.itpub.net/267265/viewspace-2565245/=> [20190130]删除tab$记录的恢复.txt
http://blog.itpub.net/267265/viewspace-2565250/=> [20190130]删除tab$记录的恢复2.txt

--//实际上我一直认为能拷贝出来数据就ok了.这样恢复的数据库不能在使用,问题多多.
--//我继续测试实际上建表等操作都会报类似的:
ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [94232], [6110], [], [], [], [], [], [], [], []
--//这样的错误.主要问题在于system块的检查更加严格.

--//今天尝试恢复6110,6111,6112之类的错误.

1.环境:

  1. SCOTT@book> @ ver1
  2. PORT_STRING VERSION BANNER
  3. ------------------------------ -------------- --------------------------------------------------------------------------------
  4. x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production


--//前面已经恢复只读状态exp操作是正常的.具体看前面的文章.
--//首先更正前面脚本的几个错误:http://blog.itpub.net/267265/viewspace-2565250/=> [20190130]删除tab$记录的恢复2.txt

  1. 57 echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^^flag@.*: *0x7c" > /dev/null
  2. --//原来写成echo "x /rx dba $dba *kdbr[$begin]" | rlbbed | egrep "^^flag@.*: 0x7c" > /dev/null ,可能出现多个空格的情况.
  3. 58 if [ $? -eq 0 ]
  4. 59 then
  5. 60 echo "dba=$dba;ckix_value=0" >> scan4a.txt
  6. 61 fi
  7. $ cat scana.sh
  8. #! /bin/bash
  9. cat clearout.txt | while read dba
  10. do
  11. echo set dba $dba
  12. echo -n "assign "
  13. echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$"| egrep "ktbbhitl|ktbitflg" | cut -c11-21,55-60 | paste -d. - - | sed -e 's/ /=/'
  14. --//这里写错,原来写成4204236,实际上应该是$dba,
  15. echo sum apply dba $dba
  16. done
  17. --//注:http://blog.itpub.net/267265/viewspace-2565250/=> [20190130]删除tab$记录的恢复2.txt 里面的脚本已经更正.


2.我前面做了冷备份.首先恢复冷备份:

  1. $ /bin/cp -r /home/oracle/backup/book_20190122_bad/* /mnt/ramdisk/book/
  2. */
  3. $ . scan.sh
  4. process 1 start : 2019/02/12 08:45:44 scan dba 1,144 , create scan1.txt about ktetbdba,ktetbnbk
  5. process 1 finish: 2019/02/12 08:45:44,enter continue...
  6. process 2 start : 2019/02/12 08:45:45 scan block , get kdbtnrow,kdbtoffs ang grep kdbtnrow=0
  7. process 2 finish: 2019/02/12 08:46:16,enter continue...
  8. process 3 start : 2019/02/12 08:46:50 scan block , create bbed'script scan3_bbed.txt for modify delete of flag and create scan4a.txt about block of ckix
  9. process 3 finish: 2019/02/12 08:52:01,enter continue...
  10. process 4 start : 2019/02/12 08:52:06 create bbed's scan4_bbed.txt for modify cluster of mref of value
  11. process 4 finish: 2019/02/12 08:53:12,enter continue...
  12. process 5 start : create bbed's scan5_bbed.txt for sum apply
  13. process 5 finish: 2019/02/12 08:54:11,enter continue...


--//查看生成的bbed脚本:

  1. $ cat scan4m_bbed.txt
  2. assign dba 4288539 offset 8169 = 1
  3. assign dba 4288546 offset 8145 = 1


--//前面我提到过这2块dba的不需要恢复(里面记录的scn不是这个事务产生的),或者讲scan4m_bbed.txt脚本记录的dba可能存在多恢复记录的情况.最好仔细检查.

  1. $ grep -v 0x6c scan3_bbed.txt
  2. assign /x dba 4194451 offset 7349 = 0x20
  3. assign /x dba 4197642 offset 7888 = 0x20
  4. assign /x dba 4207636 offset 7087 = 0x20
  5. assign /x dba 4225801 offset 3621 = 0x4c
  6. assign /x dba 4225801 offset 4436 = 0x4c
  7. assign /x dba 4288537 offset 7717 = 0x4c


--//这3条记录存在行链接或者迁移的情况,前面已经解析不再说明.
--//修改scan3_bbed.txt文件,注解如下2行不需要恢复.

  1. $ grep ^# scan3_bbed.txt
  2. #assign /x dba 4288539 offset 7920 = 0x6c
  3. #assign /x dba 4288546 offset 7851 = 0x6c
  4. $ grep 0x6c scan3_bbed.txt | grep -v "^#" |wc
  5. 2963 23704 124395


--//2963+3=2966,这样恢复的记录数量与实际情况相符.

3.执行生成的bbed脚本并修复块 6110,6111,6112错误.

  1. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan3_bbed.txt
  2. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan4k_bbed.txt
  3. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan5_bbed.txt


--//前面提到启动遇到如下错误,主要是因为延迟块提交的问题:

  1. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [94232], [6110], [], [], [], [], [], [], [], []
  2. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [9951], [6110], [], [], [], [], [], [], [], []
  3. ORA-00600: internal error code, arguments: [kdBlkCheckError], [1], [31548], [6110], [], [], [], [], [], [], [], []


--//编写脚本如下,主要获得延迟块提交的数据块,设置提交标识.并且将对应的ktbbhitl[N]._ktbitun._ktbitfsc=0.
--//这样会导致verify时出现如下错误,例子:

  1. BBED> set dba 4204236
  2. DBA 0x004026cc (4204236 1,9932)
  3. BBED> verify
  4. DBVERIFY - Verification starting
  5. FILE = /mnt/ramdisk/book/system01.dbf
  6. BLOCK = 9932
  7. Block Checking: DBA = 4204236, Block Type = KTB-managed data block
  8. data header at 0x7fb110a7b25c
  9. kdbchk: space available on commit is incorrect
  10. tosp=5052 fsc=0 stb=0 avsp=4937
  11. Block 9932 failed with check code 6111


--//解决方法就是assign kdbhtosp=kdbhavsp;sum apply就ok了.
--//我以前处理这个错误有点繁琐.实际上设置fsc=0,设置提交标识为快速提交标识0x2,在执行assign kdbhtosp=kdbhavsp,
--//这样记录里面lock标识不需要设置为0x0,这样简单许多.

  1. $ cat scanb.sh
  2. #! /bin/bash
  3. # get dba of tailchk ,grep begin # line, save scan6.txt
  4. # and then grep -v 0x5f5f06,save clearout.txt,other save notclearout.txt
  5. grep dba scan3_bbed.txt | grep -v "^#" | cut -d" " -f4 | uniq | while read dba
  6. do
  7. echo -n $dba :
  8. echo "p dba $dba offset 0 tailchk 8188"| rlbbed | grep "ub4 tailchk"
  9. done >| scan6.txt
  10. grep -v 0x5f5f06 scan6.txt >| clearout.txt
  11. grep 0x5f5f06 scan6.txt >| notclearout.txt
  12. # create modify ktbbhitl[N].ktbitflg , ktbbhitl[N]._ktbitun._ktbitfsc=0 and kdbhtosp=kdbhavsp of script.
  13. cat clearout.txt | cut -d" " -f1 |while read dba
  14. do
  15. echo set dba $dba
  16. echo -n "assign "
  17. echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$"| egrep "ktbbhitl|ktbitflg" | cut -c11-21,55-60 | paste -d. - - | sed -e 's/ /=/'
  18. echo -n "assign "
  19. echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$" | egrep "ktbbhitl"| cut -c11-21 | sed -e 's/$/._ktbitun._ktbitfsc=0/'
  20. echo "assign kdbhtosp=kdbhavsp"
  21. echo sum apply dba $dba
  22. done >| clearout_bbed.txt
  23. # create modify ktbbhitl[N]._ktbitun._ktbitfsc=0 and kdbhtosp=kdbhavsp of script.
  24. cat notclearout.txt | cut -d" " -f1 |while read dba
  25. do
  26. echo set dba $dba
  27. # echo -n "assign "
  28. # echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$"| egrep "ktbbhitl|ktbitflg" | cut -c11-21,55-60 | paste -d. - - | sed -e 's/ /=/'
  29. echo -n "assign "
  30. echo -e "set dba $dba \np ktbbh" |rlbbed | /bin/grep -B 4 -A 9 "ub4 kxidsqn \+@.*0x00000751$" | egrep "ktbbhitl"| cut -c11-21 | sed -e 's/$/._ktbitun._ktbitfsc=0/'
  31. echo "assign kdbhtosp=kdbhavsp"
  32. echo sum apply dba $dba
  33. done >| notclearout_bbed.txt


--//执行以上脚本:

  1. $ . scanb.sh
  2. $ grep "ktbbhitl[1].ktbitflg=" clearout_bbed.txt | grep -v 0x0
  3. $ echo $?
  4. 1


--//说明这些块都没有打上提交标识.

  1. $ head -5 clearout_bbed.txt
  2. set dba 4204236
  3. assign ktbbhitl[1].ktbitflg=0x0002
  4. assign ktbbhitl[1]._ktbitun._ktbitfsc=0
  5. assign kdbhtosp=kdbhavsp
  6. sum apply dba 4204236


--//使用vim执行:%s/ktbitflg=0x0/ktbitflg=0x2/.也就是设置提交标识.注意检查替换是否74行.
--//补充说明一下,我前面测试执行的是%s/=0x00/=0x20/,实际上提交标识仅仅占半个字节(4位),这样写有点问题,不过一般不会出现问题.
--//1块修改255条以上的情况在这里不会出现(至少对于这个表是如此).

  1. $ head -5 clearout_bbed.txt
  2. set dba 4204236
  3. assign ktbbhitl[1].ktbitflg=0x2002
  4. assign ktbbhitl[1]._ktbitun._ktbitfsc=0
  5. assign kdbhtosp=kdbhavsp
  6. sum apply dba 4204236


--//执行如下:

  1. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/clearout_bbed.txt
  2. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/notclearout_bbed.txt
  3. $ dbv file=/mnt/ramdisk/book/system01.dbf
  4. DBVERIFY: Release 11.2.0.4.0 - Production on Tue Feb 12 10:37:09 2019
  5. Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
  6. DBVERIFY - Verification starting : FILE = /mnt/ramdisk/book/system01.dbf
  7. DBVERIFY - Verification complete
  8. Total Pages Examined : 97280
  9. Total Pages Processed (Data) : 64316
  10. Total Pages Failing (Data) : 0
  11. Total Pages Processed (Index): 13442
  12. Total Pages Failing (Index): 0
  13. Total Pages Processed (Other): 4185
  14. Total Pages Processed (Seg) : 1
  15. Total Pages Failing (Seg) : 0
  16. Total Pages Empty : 15337
  17. Total Pages Marked Corrupt : 0
  18. Total Pages Influx : 0
  19. Total Pages Encrypted : 0
  20. Highest block SCN : 393502590 (3.393502590)


--//现在OK了.
4.禁用sys.tab$的索引I_TAB1.

--//这样恢复,索引与表存在不一致情况,要禁用sys.tab$的索引I_TAB1.

  1. BBED> x /rnnc dba 1,523 *kdbr[9]
  2. rowdata[1269] @4910
  3. -------------
  4. flag@4910: 0x2c (KDRHFL, KDRHFF, KDRHFH)
  5. lock@4911: 0x01
  6. cols@4912: 3
  7. col 0[2] @4913: 33
  8. col 1[2] @4916: 33
  9. 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
  10. 645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BLOCK 312))


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

  1. BBED> assign /x dba 1,523 offset 4910= 0x3c
  2. Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
  3. ub1 rowdata[0] @4910 0x3c
  4. BBED> sum apply dba 1,523
  5. Check value for File 1, Block 523:
  6. current = 0x7e6b, required = 0x7e6b
  7. BBED> verify dba 1,523
  8. DBVERIFY - Verification starting
  9. FILE = /mnt/ramdisk/book/system01.dbf
  10. BLOCK = 523
  11. Block Checking: DBA = 4194827, Block Type = KTB-managed data block
  12. data header at 0x6eee44
  13. kdbchk: the amount of space used is not equal to block size
  14. used=4398 fsc=0 avsp=3525 dtl=8120
  15. Block 523 failed with check code 6110


--//先不理会这个错误.

5.启动数据库看看:
 

  1. SYS@book> startup pfile='/tmp/@.ora';
  2. ORACLE instance started.
  3. Total System Global Area 643084288 bytes
  4. Fixed Size 2255872 bytes
  5. Variable Size 205521920 bytes
  6. Database Buffers 427819008 bytes
  7. Redo Buffers 7487488 bytes
  8. Database mounted.
  9. Database opened.
  10. SYS@book> shutdown immediate ;
  11. Database closed.
  12. Database dismounted.
  13. ORACLE instance shut down.
  14. SYS@book> startup open read only pfile='/tmp/book.ora'
  15. ORACLE instance started.
  16. Total System Global Area 643084288 bytes
  17. Fixed Size 2255872 bytes
  18. Variable Size 205521920 bytes
  19. Database Buffers 427819008 bytes
  20. Redo Buffers 7487488 bytes
  21. Database mounted.
  22. Database opened.


--//注/tmp/book.ora最好加入修改如下:

  1. *._system_trig_enabled=false
  2. *.job_queue_processes=0
  3. SYS@book> select * from sys.tab$ minus select * from orachk001;
  4. no rows selected
  5. SYS@book> select * from orachk001 minus select * from sys.tab$;
  6. no rows selected


--//OK,几乎完美恢复.我执行如下select * from sh.sales;,顺利读出,没有任何问题.
--//现在建立删除表没有任何问题.

  1. SCOTT@book> create table t as select * from all_objects;
  2. Table created.
  3. SCOTT@book> drop table t purge ;
  4. Table dropped.


6.剩下恢复tab$.索引I_TAB1,

写得有点长.另写一篇修复索引的帖子,感觉这步很难,也许要先放一放.
--//最后说明一点,我的是测试环境,也许真实的环境更加复杂.我可能还遗漏一些细节...^_^.

[20190226]删除tab$记录的恢复6.txt


--//春节前几天做了删除tan$记录的测试,链接:
http://blog.itpub.net/267265/viewspace-2565245/=> [20190130]删除tab$记录的恢复.txt
http://blog.itpub.net/267265/viewspace-2565250/=> [20190130]删除tab$记录的恢复2.txt

--//我这样恢复后,仅仅能读,不能建表等操作,必须解决bbed verify报6110,6111,6112之类的错误问题.链接:
http://blog.itpub.net/267265/viewspace-2629866/=> [20190212]删除tab$记录的恢复3.txt

--//当时这些恢复,我tab$的索引i_tab1是禁用的.今天尝试恢复索引看看.
--//做了这个测试:链接https://www.cnblogs.com/lfree/p/10438177.html


1.环境:

  1. SYS@book> @ ver1
  2. PORT_STRING VERSION BANNER
  3. ------------------------------ -------------- --------------------------------------------------------------------------------
  4. x86_64/Linux 2.4.xx 11.2.0.4.0 Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
  5. SYS@book> select rowid,a.* from SYS.BOOTSTRAP$ a where a.sql_text like '%I_TAB1%';
  6. ROWID LINE# OBJ# SQL_TEXT
  7. ------------------ ---------- ---------- ------------------------------------------------------------
  8. AAAAA7AABAAAAILAAJ 33 33 CREATE INDEX I_TAB1 ON TAB$(BOBJ#) PCTFREE 10 INITRANS 2 MAX
  9. TRANS 255 STORAGE ( INITIAL 64K NEXT 1024K MINEXTENTS 1 MAX
  10. EXTENTS 2147483645 PCTINCREASE 0 OBJNO 33 EXTENTS (FILE 1 BL
  11. OCK 312))
  12. SYS@book> select count(*) from tab$ where BOBJ# is not null ;
  13. COUNT(*)
  14. ----------
  15. 139



--//可以发现索引的键值仅仅139个,也就是索引很小.可以尝试使用bbed解决这个问题.
--//索引段头在dba =1,312,这样索引root节点在dba =1,313.



2.先观察没有删除的情况:

  1. BBED> info all
  2. File# Name Size(blks)
  3. ----- ---- ----------
  4. 1 /mnt/ramdisk/book/system01.dbf 0
  5. 101 /home/oracle/backup/book_20190122_good/system01.dbf 0
  6. 201 /home/oracle/backup/book_20190122_bad/system01.dbf 0
  7. BBED> set dba 1,313
  8. DBA 0x00400139 (4194617 1,313)
  9. BBED> p kd_off
  10. sb2 kd_off[0] @124 8032
  11. sb2 kd_off[1] @126 0
  12. sb2 kd_off[2] @128 8020
  13. sb2 kd_off[3] @130 7996
  14. sb2 kd_off[4] @132 7972
  15. sb2 kd_off[5] @134 7960
  16. sb2 kd_off[6] @136 7900
  17. sb2 kd_off[7] @138 7864
  18. sb2 kd_off[8] @140 7852
  19. sb2 kd_off[9] @142 7840
  20. sb2 kd_off[10] @144 7828
  21. sb2 kd_off[11] @146 7816
  22. ...
  23. sb2 kd_off[134] @392 6260
  24. sb2 kd_off[135] @394 6218
  25. sb2 kd_off[136] @396 6232
  26. sb2 kd_off[137] @398 6190
  27. sb2 kd_off[138] @400 6204



--//正好139个行目录.在一个块里面修复相对简单.
--//注:bbed看索引块存在问题,实际上kd_off[0], kd_off[1]记录的偏移量不对.实际上从kd_off[2]开始.

  1. BBED> x /rnx dba 1,313 *kd_off[2]
  2. rowdata[2002] @8112
  3. -------------
  4. flag@8112: 0x00 (NONE)
  5. lock@8113: 0x00
  6. data key:
  7. col 0[2] @8115: 2
  8. col 1[6] @8118: 0x00 0x40 0x00 0x91 0x00 0x00
  9. BBED> x /rnx dba 201,313 *kd_off[2]
  10. rowdata[2002] @8112
  11. -------------
  12. flag@8112: 0x01 (KDXRDEL)
  13. lock@8113: 0x02
  14. data key:
  15. col 0[2] @8115: 2
  16. col 1[6] @8118: 0x00 0x40 0x00 0x91 0x00 0x00



--//注:201是删除tab$的对应的数据文件.可以发现删除键值的flag=0x01.
--//这样恢复就简单了.但是注意这样遗漏2条索引键值记录.
 

$ seq 2 138 | xargs -I{} echo 'x /rnx dba 201,313 *kd_off[{}]' | rlbbed | grep -B1 "^lock@.*:*0x02$"  | grep "^flag@.*:.*0x01"|cut -d: -f1 | cut -d@ -f2 | xargs -I{} echo assign dba 1,313 offset {}=0x00 > index_bbed.txt


--//grep 过滤lock的相关信息你的测试可能与我的不同(可能使用不同itl槽处理事务),根据实际需要修改.
--//注意:我写的脚本坏文件号为201.

  1. $ head -3 index_bbed.txt
  2. assign dba 1,313 offset 8112=0x00
  3. assign dba 1,313 offset 8088=0x00
  4. assign dba 1,313 offset 8064=0x00
  5. $ tail -3 index_bbed.txt
  6. assign dba 1,313 offset 6324=0x00
  7. assign dba 1,313 offset 6282=0x00
  8. assign dba 1,313 offset 6296=0x00
  9. $ wc index_bbed.txt
  10. 137 685 4658 index_bbed.txt



--//137条,还差2条.
 

  1. BBED> p kd_off[138]
  2. sb2 kd_off[138] @400 6204
  3. BBED> dump offset 402 count 4
  4. File: /mnt/ramdisk/book/system01.dbf (1)
  5. Block: 313 Offsets: 402 to 405 Dba:0x00400139
  6. ---------------------------------------------------------
  7. 94178617
  8. <64 bytes per line>



--//说明: kd_off[138]的偏移量记录在偏移400,下面2条记录的偏移记录从402算起.
--// 9417 颠倒过来就是  0x1794=6036, 记录相对偏移从kdxle算起(当前是92,通过map命令可以确定kdxle的偏移), 6036+92 = 6128.
--// 8617 颠倒过来就是  0x1786=6022, 记录相对偏移从kdxle算起(当前是92,通过map命令可以确定kdxle的偏移), 6022+92 = 6114.

  1. BBED> x /rnx dba 201,313 offset 6128
  2. rowdata[18] @6128
  3. -----------
  4. flag@6128: 0x01 (KDXRDEL)
  5. lock@6129: 0x02
  6. data key:
  7. col 0[4] @6131: 90426
  8. col 1[6] @6136: 0x00 0x41 0x70 0x1e 0x00 0x01
  9. BBED> x /rnx dba 201,313 offset 6114
  10. rowdata[4] @6114
  11. ----------
  12. flag@6114: 0x01 (KDXRDEL)
  13. lock@6115: 0x02
  14. data key:
  15. col 0[4] @6117: 90426
  16. col 1[6] @6122: 0x00 0x41 0x70 0x1e 0x00 0x02


--//追加如下2行到index_bbed.txt

  1. echo assign dba 1,313 offset 6128=0x00 >> index_bbed.txt
  2. echo assign dba 1,313 offset 6114=0x00 >> index_bbed.txt


3.开始尝试索引恢复:
--//先关闭数据库.恢复坏的数据库.

  1. $ /bin/cp -r /home/oracle/backup/book_20190122_bad/* /mnt/ramdisk/book
  2. */


--//执行前面测试生成的脚本:

  1. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan3_bbed.txt
  2. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan4k_bbed.txt
  3. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/clearout_bbed.txt
  4. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/notclearout_bbed.txt
  5. bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/scan5_bbed.txt



--//修复索引标识标本.
bbed parfile=/home/oracle/bbed/bbed.par cmdfile=/home/oracle/hrp430/bbed/index_bbed.txt

--//以下是修复一些错误.

  1. BBED> set dba 1,313
  2. DBA 0x00400139 (4194617 1,313)
  3. BBED> sum apply
  4. Warning: contents of previous BIFILE will be lost. Proceed? (Y/N) y
  5. Check value for File 1, Block 313:
  6. current = 0x9b89, required = 0x9b89
  7. BBED> verify
  8. DBVERIFY - Verification starting
  9. FILE = /mnt/ramdisk/book/system01.dbf
  10. BLOCK = 313
  11. Block Checking: DBA = 4194617, Block Type = KTB-managed data block
  12. **** actual free space = 3700 < kdxcoavs = 5848
  13. **** actual rows marked deleted = 0 != kdxlende = 139
  14. ---- end index block validation
  15. Block 313 failed with check code 6401
  16. BBED> p kdxle.kdxlende
  17. sb2 kdxlende @110 139
  18. BBED> assign kdxle.kdxlende =0
  19. sb2 kdxlende @110 0
  20. BBED> sum apply
  21. Check value for File 1, Block 313:
  22. current = 0x9b02, required = 0x9b02
  23. BBED> verify
  24. DBVERIFY - Verification starting
  25. FILE = /mnt/ramdisk/book/system01.dbf
  26. BLOCK = 313
  27. Block Checking: DBA = 4194617, Block Type = KTB-managed data block
  28. **** actual free space = 3700 < kdxcoavs = 5848
  29. ---- end index block validation
  30. Block 313 failed with check code 6401
  31. BBED> p kdxle.kdxlexco.kdxcoavs
  32. sb2 kdxcoavs @106 5848
  33. BBED> assign kdxle.kdxlexco.kdxcoavs= 3700
  34. sb2 kdxcoavs @106 3700
  35. BBED> sum apply
  36. Check value for File 1, Block 313:
  37. current = 0x83ae, required = 0x83ae
  38. BBED> verify
  39. DBVERIFY - Verification starting
  40. FILE = /mnt/ramdisk/book/system01.dbf
  41. BLOCK = 313


--//OK,现在修复了.



4.启动检查数据库情况:

  1. SYS@book> startup
  2. ORACLE instance started.
  3. Total System Global Area 643084288 bytes
  4. Fixed Size 2255872 bytes
  5. Variable Size 205521920 bytes
  6. Database Buffers 427819008 bytes
  7. Redo Buffers 7487488 bytes
  8. Database mounted.
  9. Database opened.
  10. SYS@book> select * from sys.tab$ minus select * from orachk001;
  11. no rows selected
  12. SYS@book> select * from orachk001 minus select * from sys.tab$;
  13. no rows selected
  14. SYS@book> ANALYZE TABLE sys.tab$ VALIDATE STRUCTURE CASCADE;
  15. Table analyzed.
  16. SYS@book> select count(*) from sys.tab$ where BOBJ# is not null ;
  17. COUNT(*)
  18. ----------
  19. 139
  20. SYS@book> @ dpc '' ''
  21. PLAN_TABLE_OUTPUT
  22. -------------------------------------
  23. SQL_ID 7nkaks3h1mmd2, child number 0
  24. -------------------------------------
  25. select count(*) from sys.tab$ where BOBJ# is not null
  26. Plan hash value: 3621218687
  27. ----------------------------------------------------------------------------
  28. | Id | Operation | Name | E-Rows |E-Bytes| Cost (%CPU)| E-Time |
  29. ----------------------------------------------------------------------------
  30. | 0 | SELECT STATEMENT | | | | 1 (100)| |
  31. | 1 | SORT AGGREGATE | | 1 | 2 | | |
  32. |* 2 | INDEX FULL SCAN| I_TAB1 | 139 | 278 | 1 (0)| 00:00:01 |
  33. ----------------------------------------------------------------------------
  34. Query Block Name / Object Alias (identified by operation id):
  35. -------------------------------------------------------------
  36. 1 - SEL$1
  37. 2 - SEL$1 / TAB$@SEL$1
  38. Predicate Information (identified by operation id):
  39. ---------------------------------------------------
  40. 2 - filter("BOBJ#" IS NOT NULL)


--//可以正常读取索引,到此删除tab$的恢复包括索引已经完美完成.累...........

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/186497
推荐阅读
相关标签
  

闽ICP备14008679号