首页 > 数据库 > Oracle > [20210319]bbed读取数据块3.txt
[20210319]bbed读取数据块3.txt
--//昨天做了bbed读取数据块链接:http://blog.itpub.net/267265/viewspace-2763810/
--//今天测试一些特殊情况使用它恢复会出现什么情况,算是做一些补充。
--//注意不要拿它到生产系统测试:
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
--//drop table t purge ;
SCOTT@book> create table t as select * from all_objects where rownum<=1000;
Table created.
SCOTT@book> select object_id,data_object_id from dba_objects where owner=user and object_name='T';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
90982 90982
SCOTT@book> select rowid from t where rownum=1;
ROWID
------------------
AAAWNmAAEAAAALbAAA
SCOTT@book> @ rowid AAAWNmAAEAAAALbAAA
OBJECT FILE BLOCK ROW ROWID_DBA DBA TEXT
---------- ---------- ---------- ---------- -------------------- -------------------- ----------------------------------------
90982 4 731 0 0x10002DB 4,731 alter system dump datafile 4 block 731 ;
SCOTT@book> @ bbedcol scott t
DISPLAY BBED EXAMINE(X) FORMAT
C80
---------------
cccnncttcccccnc
2.建立脚本,测试读取看看。
--//注脚本做一些修改,增加bbed /x 的格式,代码更加通用一些,注意我没有做参数检查。
$ cat fff.sh
#! /bin/bash -x
# argv1=file_number argv2=begin_block argvs3=end_block argv4=data_object_id argv5=bbed /x format
file_number=$1
begin_block=$2
end_block=$3
data_object_id=$4
ff="/r"${5}
# scan1 begin_block to end_block,define Scope.
/bin/rm scan1.txt
while [ $begin_block -le $end_block ]
do
v_object_id=$(echo "p /d dba $file_number,$begin_block ktbbh.ktbbhsid.ktbbhod1" | rlbbed | grep ktbbhod1 |awk '{print $NF}')
if [ -z "$v_object_id" ]
then
v_object_id=0
fi
if (( $v_object_id == $data_object_id ))
then
echo $file_number,$begin_block >> scan1.txt
fi
begin_block=$[ begin_block + 1 ]
done
# scan2 kdbr and display record.
cat scan1.txt |while read dba
do
#echo set dba $dba
kdbr_size=$(echo map dba $dba | rlbbed | grep "sb2 kdbr" | sed -e "s/^.*\[//;s/].*$//")
#echo $kdbr_size
begin=0
end=$[ kdbr_size -1 ]
#echo $begin $end
while [ $begin -le $end ]
do
kdbr_off=$(echo p dba $dba offset 0 kdbr | rlbbed | grep "sb2 kdbr\[$begin\]" | awk '{print $NF'})
#echo $kdbr_off
#if [ $kdbr_off -gt $kdbr_size ]
if (( $kdbr_off > $kdbr_size ))
then
echo -n "x $ff dba $dba *kdbr[$begin]" | rlbbed | grep "^col " | cut -c20- | paste -sd'|'
fi
begin=$[ begin + 1 ]
done
done
3.恢复看看:
$ . fff.sh 4 731 800 90982 cccnncttcccccnc |wc
1000 6944 119676
--//不做导入测试了。
--//使用toad导入
--//整理本文如下,使用vim的替换功能:
--//:%s+ |+|+g
--//:%s+ $++g
--//:%s+|\*NULL\*|++g
4.增加一些难度:
SCOTT@book> delete from t where mod(object_id,100)=0;
9 rows deleted.
SCOTT@book> commit ;
Commit complete.
SCOTT@book> alter system checkpoint ;
System altered.
--//注:不写盘恢复看不到改变。
$ . fff.sh 4 731 800 90982 cccnncttcccccnc >| laji.txt
--//打开laji.txt文本发现:
98 SYS|EDITION$|*NULL*|99 |99 |TABLE|2013-08-24 11:37:36 |2013-08-24 11:37:36 |2013-08-24:11:37:36|VALID|N|N|N|1
99
100 SYS|FIXED_OBJ$|*NULL*|101 |101 |TABLE|2013-08-24 11:37:36 |2013-08-24 11:37:36 |2013-08-24:11:37:36|VALID|N|N|N|1
--//删除的记录显示为空行,这个问题都不是很大,脚本可以处理掉,也可以通过vim编辑去掉或者grep过滤。
--//做一个update看看行迁移会出现什么情况。
SCOTT@book> update t set owner=lpad('A',30,'A') where DBMS_ROWID.ROWID_BLOCK_NUMBER (rowid)=731;
88 rows updated.
SCOTT@book> commit ;
Commit complete.
SCOTT@book> alter system checkpoint ;
System altered.
$ . fff.sh 4 731 731 90982 cccnncttcccccnc >| laji.txt
--//打开laji.txt文本发现:
32 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|I_COL2|*NULL*|49 |49 |INDEX|2013-08-24 11:37:35 |2013-08-24 11:37:35 |2013-08-24:11:37:35|VALID|N|N|N|4
33
34 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|I_OBJ4|*NULL*|39 |39 |INDEX|2013-08-24 11:37:35 |2013-08-24 11:37:35 |2013-08-24:11:37:35|VALID|N|N|N|4
BBED> x /rcccnncttcccccnc dba 4,731 *kdbr[32]
rowdata[4396] @4781
-------------
flag@4781: 0x20 (KDRHFH)
lock@4782: 0x02
cols@4783: 0
nrid@4784:0x010002fd.0
--//出现行迁移,麻烦的是如果部分内容在块中,另外的数据在另外块中,使用bbed恢复难度更大。
--//0x010002fd = set dba 4,765 = alter system dump datafile 4 block 765 = 16777981
--//真实的数据在dba=4,765.
BBED> x /rcccnncttcccccnc dba 4,765 *kdbr[0]
rowdata[1692] @8077
-------------
flag@8077: 0x0c (KDRHFL, KDRHFF)
lock@8078: 0x01
cols@8079: 14
hrid@8080:0x010002db.20
col 0[30] @8086: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
col 1[6] @8117: I_OBJ2
col 2[0] @8124: *NULL*
col 3[2] @8125: 37
col 4[2] @8128: 37
col 5[5] @8131: INDEX
col 6[7] @8137: 2013-08-24 11:37:35
col 7[7] @8145: 2013-08-24 11:37:35
col 8[19] @8153: 2013-08-24:11:37:35
col 9[5] @8173: VALID
col 10[1] @8179: N
col 11[1] @8181: N
col 12[1] @8183: N
col 13[2] @8185: 4
$ . fff.sh 4 765 765 90982 cccnncttcccccnc | grep I_OBJ2
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA|I_OBJ2|*NULL*|37 |37 |INDEX|2013-08-24 11:37:35 |2013-08-24 11:37:35 |2013-08-24:11:37:35|VALID|N|N|N|4
--//在另外的块中可以看到完整记录。
$ . fff.sh 4 731 800 90982 cccnncttcccccnc | grep "^[A-Z]" | wc
991 6883 120845
$ . fff.sh 4 731 800 90982 cccnncttcccccnc | grep -v "^$" |wc
991 6883 120845
--// 1000-9 = 991,可以发现我的测试恢复没有丢失数据,因为发生行迁移是整体迁移,出现行链接bbed就比较麻烦。
5.总结:
--//不是很实用,如果delete记录,输出会出现空行。而且记录多,处理起来很慢。
--//无法解决行链接和行迁移问题。
--//另外有人问如果truncate后如何知道以前的DATA_OBJECT_ID。你可以找靠近段头的块,做一个转储就知道。
--//我记忆里logminer也能找到原来的DATA_OBJECT_ID。也可以使用as of timestamp方式查看使用sys用户查看,
--//不知道12c以上是否可行。
SCOTT@book> select sysdate from dual;
SYSDATE
-------------------
2021-03-19 16:25:44
SCOTT@book> truncate table t;
Table truncated.
SCOTT@book> select object_id,data_object_id from dba_objects where owner=user and object_name='T';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
90982 90984
SYS@book> select object_id,data_object_id from dba_objects as of timestamp to_date('2021-03-19 16:25:44','yyyy-mm-dd hh24:mi:ss') where owner='SCOTT' and object_name='T';
OBJECT_ID DATA_OBJECT_ID
---------- --------------
90982 90982
--//再次声明千万别在生产系统做这样的测试!!
6.附上bbedcol脚本语句:
$ cat bbedcol12.sql
prompt
PROMPT DISPLAY BBED EXAMINE(X) FORMAT
prompt
SELECT REPLACE (LISTAGG (c1, ',') WITHIN GROUP (ORDER BY column_id), ',') c80
FROM ( SELECT data_type
,column_id
,column_name
,DECODE
(
data_type
,'NUMBER', 'n'
,'CHAR', 'c'
,'VARCHAR', 'c'
,'VARCHAR2', 'c'
,'DATE', 't'
,' '
)
c1
FROM dba_tab_cols
WHERE owner = UPPER (NVL ('&1', USER))
AND TABLE_NAME = UPPER ('&2')
AND hidden_column = 'NO'
ORDER BY SEGMENT_COLUMN_ID);
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/267265/viewspace-2763861/ ,如需转载,请注明出处,否则将追究法律责任。