You are on page 1of 11

[oracle@localhost ~]$ vi par.

txt
blocksize=8192
listfile=filelist.txt
mode=edit

[oracle@localhost ~]$ export ORACLE_SID=newtest


[oracle@localhost ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.4.0 Production on Thu Mar 15 21:35:44 2018
Copyright (c) 1982, 2013, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select file#||chr(9)||name||chr(9)||bytes from v$datafile;

FILE#||CHR(9)||NAME||CHR(9)||BYTES
--------------------------------------------------------------------------------
1 /home/oracle/app/oradata/newtest/system01.dbf 786432000
2 /home/oracle/app/oradata/newtest/sysaux01.dbf 1006632960
3 /home/oracle/app/oradata/newtest/undotbs01.dbf 78643200
4 /home/oracle/app/oradata/newtest/users01.dbf 355205120
5 /home/oracle/app/oradata/newtest/users02.dbf 524288000

[oracle@localhost ~]$ vi filelist.txt


1 /home/oracle/app/oradata/newtest/system01.dbf 786432000
2 /home/oracle/app/oradata/newtest/sysaux01.dbf 922746880
3 /home/oracle/app/oradata/newtest/undotbs01.dbf 78643200
4 /home/oracle/app/oradata/newtest/users01.dbf 121896960

#修改 bash_profile,添加参数等
[oracle@localhost ~]$ vi .bash_profile

alias bbed='bbed parfile=par.txt password=blockedit'

#进入 bbed
[oracle@localhost ~]$ bbed
BBED: Release 2.0.0.0.0 - Limited Production on Thu Mar 15 22:17:40 2018
Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.
************* !!! For Oracle Internal Use only !!! ***************
BBED>
3.常用命令
set file 4 block 32
set dba 0x01000020
set offset 0 -- 0 表示第一个字节开始
set block 1 -- 1 表示第一个块开始
set count 8192 -- 默认是显示 512 字节
find /x 05d67g
#查指定的字符串在指定数据块中的具体位置
f --find 的简写,表示继续从当前位置开始往下查询字符串 05d67g
dump
#十六进制查看 block
dump /v --查看十六进制内容的同时以文本方式“翻译”十六进制显示的内容,相当于对当
block 执行 strings 命令
modify /x d43 #修改指定 block,指定 offset 的数据块块内记录的内容
sum apply #计算修改后的数据块的 checksum 值,然后写入数据块的 offset 为 16-17 的位置

SET DBA [ dba | file#, block# ] -----设置(data block address file#+block#)


SET FILENAME 'filename' -----设置哪个文件的名称
SET FILE file# -----设置文件号
SET BLOCK [+/-]block# -----设置块号
SET OFFSET [ [+/-]byte offset | symbol | *symbol ] -----设置偏移量,字节为单位
SET BLOCKSIZE bytes -----设置块的大小(8192)
SET LIST[FILE] 'filename' -----设置文件列表
SET WIDTH character_count -----设置显示宽度
SET COUNT bytes_to_display -----设置显示的字节 bytes 数
SET IBASE [ HEX | OCT | DEC ] ---设置进制的模式
SET OBASE [ HEX | OCT | DEC ] -----
SET MODE [ BROWSE | EDIT ] ---设置操作模式,查看还是编辑
SET SPOOL [ Y | N ] -----是否保存操作日志

首先我们有一个表为
SQL> select * from t2;
ID NAME
---------- ----------------------------------------------------------------------------------------------------
1 AAAAA
1 BBBBB
1 CCCCC
1 DDDDD
1 EEEEE

查询出每行的所在的 dba
SQL> select id,name,dbms_rowid.ROWID_RELATIVE_FNO(rowid) file#,dbms_rowid.ROWID
_BLOCK_NUMBER(rowid) block# from t2;
ID NAME FILE# BLOCK#
---------- ----------------------------------------------------------------------------------------------------
1 AAAAA 4 189
1 BBBBB 4 189
1 CCCCC 4 189
1 DDDDD 4 189
1 EEEEE 4 189

可以得出这个表的所有记录都在 4 号文件的 189 号块上


BBED> set dba 4,189
DBA 0x010000bd (16777405 4,189)

BBED> show all


FILE# 4
BLOCK# 189
OFFSET 0
DBA 0x010000bd (16777405 4,189)
FILENAME /app/oracle/oradata/orcl/users01.dbf
BIFILE bifile.bbd
LISTFILE /tmp/filelist.txt
BLOCKSIZE 8192
MODE Edit
EDIT Unrecoverable
IBASE Dec
OBASE Dec
WIDTH 80
COUNT 512
LOGFILE log.bbd
SPOOL No

map /v 可以看到数据块的结构
BBED> map /v
File: /app/oracle/oradata/orcl/users01.dbf (4)
Block: 189 Dba:0x010000bd
------------------------------------------------------------
KTB Data Block (Table/Cluster)

struct kcbh, 20 bytes @0


ub1 type_kcbh @0
ub1 frmt_kcbh @1
ub1 spare1_kcbh @2
ub1 spare2_kcbh @3
ub4 rdba_kcbh @4
ub4 bas_kcbh @8
ub2 wrp_kcbh @12
ub1 seq_kcbh @14
ub1 flg_kcbh @15
ub2 chkval_kcbh @16
ub2 spare3_kcbh @18

struct ktbbh, 72 bytes @20


ub1 ktbbhtyp @20
union ktbbhsid, 4 bytes @24
struct ktbbhcsc, 8 bytes @28
sb2 ktbbhict @36
ub1 ktbbhflg @38
ub1 ktbbhfsl @39
ub4 ktbbhfnx @40
struct ktbbhitl[2], 48 bytes @44

struct kdbh, 14 bytes @100


ub1 kdbhflag @100
sb1 kdbhntab @101
sb2 kdbhnrow @102
sb2 kdbhfrre @104
sb2 kdbhfsbo @106
sb2 kdbhfseo @108
sb2 kdbhavsp @110
sb2 kdbhtosp @112

struct kdbt[1], 4 bytes @114


sb2 kdbtoffs @114
sb2 kdbtnrow @116
sb2 kdbr[5] @118
ub1 freespace[8000] @128
ub1 rowdata[60] @8128
ub4 tailchk @8188
  

1. Cache Layer:Block 的第一部分,长度为 20 字节,内部数据结构名为 kcbh,包括


type_kcbh:块类型(table/index,rollback segment,temporary segment 等)
  frmt_kcbh:块格式(v6,v7,v8)
  rdba_kcbh:块地址 DBA
  bas_kcbh/wrp_kcbh:SCN
  seq_kcbh:块的序列号
  flg_kcbh:块的标志

如查看 kcbh(结合 dump):


BBED> p kcbh
struct kcbh, 20 bytes @0
ub1 type_kcbh @0 0x06
ub1 frmt_kcbh @1 0xa2
ub1 spare1_kcbh @2 0x00
ub1 spare2_kcbh @3 0x00
ub4 rdba_kcbh @4 0x010000bd
ub4 bas_kcbh @8 0x00227d0f
ub2 wrp_kcbh @12 0x0000
ub1 seq_kcbh @14 0x01
ub1 flg_kcbh @15 0x06 (KCBHFDLC, KCBHFCKV)
ub2 chkval_kcbh @16 0x129e
ub2 spare3_kcbh @18 0x0000

Block dump from disk:


buffer tsn: 4 rdba: 0x010000bd (4/189)
scn: 0x0000.00227d0f seq: 0x01 flg: 0x06 tail: 0x7d0f0601
frmt: 0x02 chkval: 0x129e type: 0x06=trans data rdba = rdba_kcbh
可以看出:flg=flg_kebh type=tyoe_kcbh chkval= chkval_kcbh frmt = frmt_kcbh(这个 oracle 的
一个算法,所有在 dump 中是 a2) seq = seq_kchb
scn: 0x0000.00227d0f = wrp_kcbh(高位).bas_kcbh(地位)
tail:保持一致性 lower scn + type + seq

2.ITLBlock header dump: 0x010000bd


Object id on Block? Y
seg/obj: 0x12c11 dba_object<br> csc: 0x00.227d0d 延迟块清除时的 SCN<br>
itc: 2 itl 的个数,此时多少个事务在对本 data block 进行操作<br>
flg: E 指用的是 ASSM,如果是 0 表示用的是 free list <br >
typ: 1 - DATA DATA 事务型的数据块
brn: 0 <br>
bdba: 0x10000b8 <br>
ver: 0x01 opc: 0
inc: 0 exflg: 0

Itl Xid Uba Flag Lck Scn/Fsc


0x01 0x0005.017.0000050e 0x00c0062e.0143.31 --U- 5 fsc 0x0000.00227d0f
0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000<br>
-Itl: ITL 事务槽号的流水编号<br>
-Xid:transac[X]tion identified(事务 ID),由 und 的段号+undo 的槽号+undo 槽号的覆盖次数三
部分组成<br>
-Uba:undo block address 记录了最近一次的该记录的前镜像(修改前的值)<br>
-Flag:C 是提交,U 是快速提交,---是未提交(Flg C=Committed U=Commit Upper Bound
T=Active at CSC)<br>
-Lck : 锁 住 了 几 行 数 据 , 对 应 有 几 个 行 锁 <br>--Scn/Fsc : Scn=SCN of commited TX;
Fsc=Free space credit(bytes)<br>
bdba: 0x010000bd
接下来看 bbed 中的 ITL
struct ktbbh, 72 bytes @20
ub1 ktbbhtyp @20 0x01 (KDDBTDATA)
union ktbbhsid, 4 bytes @24
ub4 ktbbhsg1 @24 0x00012c11
ub4 ktbbhod1 @24 0x00012c11
struct ktbbhcsc, 8 bytes @28
ub4 kscnbas @28 0x00227d0d
ub2 kscnwrp @32 0x0000
sb2 ktbbhict @36 2
ub1 ktbbhflg @38 0x32 (NONE)
ub1 ktbbhfsl @39 0x00
ub4 ktbbhfnx @40 0x010000b8
struct ktbbhitl[0], 24 bytes @44
struct ktbitxid, 8 bytes @44
ub2 kxidusn @44 0x0005
ub2 kxidslt @46 0x0017
ub4 kxidsqn @48 0x0000050e
struct ktbituba, 8 bytes @52
ub4 kubadba @52 0x00c0062e
ub2 kubaseq @56 0x0143
ub1 kubarec @58 0x31
ub2 ktbitflg @60 0x2005 (KTBFUPB)
union _ktbitun, 2 bytes @62
sb2 _ktbitfsc @62 0
ub2 _ktbitwrp @62 0x0000
ub4 ktbitbas @64 0x00227d0f
struct ktbbhitl[1], 24 bytes @68
struct ktbitxid, 8 bytes @68
ub2 kxidusn @68 0x0000
ub2 kxidslt @70 0x0000
ub4 kxidsqn @72 0x00000000
struct ktbituba, 8 bytes @76
ub4 kubadba @76 0x00000000
ub2 kubaseq @80 0x0000
ub1 kubarec @82 0x00
ub2 ktbitflg @84 0x0000 (NONE)
union _ktbitun, 2 bytes @86
sb2 _ktbitfsc @86 0
ub2 _ktbitwrp @86 0x0000
ub4 ktbitbas @88 0x00000000
  都能与 DUMP 中的相对应。

3.用户数据头
data_block_dump,data header at 0x2b2fb2e3aa64
===============
tsiz: 0x1f98 0x1f98 块的 total 总可用空间
hsiz: 0x1c 数据头部占的字节数-不固定
pbl: 0x2b2fb2e3aa64
76543210
flag=--------
ntab=1 ntab=1 --数据块属于一个表, cluster 表时不是 1
nrow=5 nrow=2 --行数
frre=-1 first free row index entry;-1=you have to add one
fsbo=0x1c free space begin offset 起始空间:可以存放数据空间的起始位置(即
定义了数据层中空闲空间的起始 offset)
fseo=0x1f5c free space end offset 结束空间:可以存放数据空间的结束位置(即定
义了数据层中空闲空间的结束 offset)
avsp=0x1f40 available space in the block 可用空间
tosp=0x1f40 total available space when all txs commit
0xe:pti[0] nrow=5 offs=0 整个表的开始,共 2 行数据 ,定义了该表在行索引中使用的插
槽数
0x12:pri[0] offs=0x1f8c 行索引,定义了该块中包含的所有行数据的位置
0x14:pri[1] offs=0x1f80
0x16:pri[2] offs=0x1f74
0x18:pri[3] offs=0x1f68
0x1a:pri[4] offs=0x1f5c

BBED 中
BBED> p kdbh
struct kdbh, 14 bytes @100
ub1 kdbhflag @100 0x00 (NONE)
sb1 kdbhntab @101 1
sb2 kdbhnrow @102 5
sb2 kdbhfrre @104 -1
sb2 kdbhfsbo @106 28
sb2 kdbhfseo @108 8028
sb2 kdbhavsp @110 8000
sb2 kdbhtosp @112 8000 

4.接下来就是用户数据
block_row_dump:
tab 0, row 0, @0x1f8c
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2 FL 开始结束, lb(lock byte), 第一个事务发生在第一个
事务槽上面 cc 有两列
col 0: [ 2] c1 02 c1 02 是 1 ,oracle 内部的算法。
col 1: [ 5] 41 41 41 41 41 41=A,所以是 AAAAA
tab 0, row 1, @0x1f80
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 5] 42 42 42 42 42
tab 0, row 2, @0x1f74
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 5] 43 43 43 43 43
tab 0, row 3, @0x1f68
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 5] 44 44 44 44 44
tab 0, row 4, @0x1f5c
tl: 12 fb: --H-FL-- lb: 0x1 cc: 2
col 0: [ 2] c1 02
col 1: [ 5] 45 45 45 45 45
end_of_block_dump<em id="__mceDel" style="background-color: #ffffff; font-family: verdana,
Arial, Helvetica, sans-serif; font-size: 14px; line-height: 1.5;"> </em>

BBED> p kdbr
sb2 kdbr[0] @118 8076
sb2 kdbr[1] @120 8064
sb2 kdbr[2] @122 8052
sb2 kdbr[3] @124 8040
sb2 kdbr[4] @126 8028
BBED> x /rnc
rowdata[48] @8176
-----------
flag@8176: 0x2c (KDRHFL, KDRHFF, KDRHFH)
lock@8177: 0x01
cols@8178: 2

col 0[2] @8179: 1


col 1[5] @8182: AAAAA

Use the verify command in bbed, along with several other outside-of-bbed utilities (analyze,
DBMS_REPAIR, etc.) to validate the block structure. Is the restored structure valid?

BBED> verify dba 4,32


DBVERIFY - Verification starting
FILE = /opt/app/oracle/oradata/ORCL2/users01.dbf
BLOCK = 32
Block Checking: DBA = 16777248, Block Type = KTB-managed data block
data header at 0x137264
kdbchk: the amount of space used is not equal to block size
used=613 fsc=38 avsp=7475 dtl=8088
Block 32 failed with check code 6110

DBVERIFY - Verification complete

Total Blocks Examined :1


Total Blocks Processed (Data) : 1
Total Blocks Failing (Data) : 1
Total Blocks Processed (Index): 0
Total Blocks Failing (Index): 0
Total Blocks Empty :0
Total Blocks Marked Corrupt : 0
Total Blocks Influx :0

In this example, the data was restored, but the block failed to validate. Once the data is restored,
take steps to check and ensure its validity. A simple way to collect the data is to perform a CTAS
(Create Table As Select) using the original table as the source. The following shows there is not a
difference, followed by evidence of one, and that the count is off by one.

SQL> select * from emp minus select * from emp2;


no rows selected

SQL> select * from emp2 minus select * from emp;


no rows selected

SQL> select empno from emp minus select empno from emp2;
no rows selected

SQL> select empno from emp2 minus select empno from emp;
EMPNO
----------
7788

SQL> select count(*) from emp;


COUNT(*)
----------
13

SQL> select count(*) from emp2;


COUNT(*)
----------
14

What can one do to remove this discrepancy? The best way - before anyone else starts trying other
options - is to do what was just mentioned: make a copy of the data and put it elsewhere. Then, if
one wants to start trying DBMS_REPAIR and other options, when one sees the following, there
will not be such a desperate feeling.

SQL> conn / as sysdba


Connected.
SQL> declare
2 fixed_count binary_integer;
3 begin
4 dbms_repair.FIX_CORRUPT_BLOCKS (
5 schema_name => 'SCOTT',
6 object_name => 'EMP',
7 partition_name => NULL,
8 object_type => dbms_repair.table_object,
9 repair_table_name => 'REPAIR_TABLE',
10 flags => NULL,
11 fix_count => fixed_count);
12 dbms_output.put_line('Fixed '||to_char(fixed_count));
13 end;
14 /
Fixed 1

PL/SQL procedure successfully completed.

SQL> conn scott/tiger


Connected.
SQL> select * from emp;
select * from emp
*
ERROR at line 1:
ORA-01578: ORACLE data block corrupted (file # 4, block # 32)
ORA-01110: data file 4: '/opt/app/oracle/oradata/ORCL2/users01.dbf'

This error leads into the next topic: corruption.


Summary
The BBED utility is extremely powerful, and if used incorrectly, can cause significant damage to a
database. On the other hand, as a means of being able to poke around inside data blocks and files,
it can be pretty handy. The best way to learn how to use this utility is to practice on a test database.
Most of the commands are self-explanatory, but several are either cryptic (only Oracle knows
what they do or how) or nonfunctional altogether. Additionally, how bbed may have function in
Oracle version 8 or 9 is no guarantee that the same set of steps will work in version 10 or 11.
Additional information
Map command - can be used with the v flag for more verbose output. It is used with the kcbh
struct to show the block header structure. Mapping against a block header and data block produces
different output. Other structs are kdbh for data header, and kdbr for row information.

Tailcheck - consists of three elements: the lower ordered two bytes of the SCN base, the block
type (typically 06 for data blocks), and the SCN sequence number.

BBED> p tailchk
ub4 tailchk @8188 0x75850602

The hex value 0x75850602 above reflects 7585 from the base, 06 for a data block, and 02 for the
sequence number.

Block header structure, found in several public sources, consists of the type, format, spare, data
block address, SCN base, SCN wrap, SCN sequence, and a flag (new, delayed logging, check
value saved and temporary, using values of 01, 02, 04 and 08). Dump the beginning of a block (at
offset 0) and this is the first line.

You might also like