BBED修復資料庫常用命令介紹

yingyifeng306發表於2021-05-06

BBED 是Block Browser/Editor的縮寫,是Oracle的一個內部工具,不對外發布文件及支援。正因為如此,所以其功能強大,可以直接修改block上的內容,因此很顯然可以透過BBED來修改表上的資料,直接繞過透過SQL語句對錶的操作。因此當資料庫出現極端的啟動故障時,可以考慮此工具作為最後的搶救手段。

 

的BBED在windows 平臺下的$ORACLE_HOME/bin下可以找到(從9i開始沒有了),而 在linux上面有,需要編譯。

在9i/10g中連線生成bbed:

       $ cd $ORACLE_HOME/rdbms/lib

       $ make-f ins_rdbms.mk $ORACLE_HOME/rdbms/lib/bbed

 BBED 是Oracle 內部使用的命令,所以Oracle 不提供技術支援。 為了安全,BBED設定了口令保護,預設密碼為blockedit。 還需要注意的是bbed直接修改檔案有很大的風險,使用需要慎重。最好先做好備份,以防出現錯誤無法回退。

     

位元組順序是指佔記憶體多於一個位元組型別的資料在記憶體中的存放順序,通常有小端(little-endian)、大端(big-endian)兩種位元組順序。小端位元組序指低位元組資料存放在記憶體低地址處,高位元組資料存放在記憶體高地址處;大端位元組序是高位元組資料存放在低地址處,低位元組資料存放在高地址處。考慮 0x1234abcd (0xcd 是低位,0x12是高位,這是人類的書寫順序), 寫入到以 0x0000 開始的記憶體地址中, 那麼它在記憶體中的儲存可能有如下兩種情況:

注意 , 我們的書寫字資料表示法是從高位元組位 ---> 低位元組位(從左到右)

如,十進位制數 “一百二十”我們手工書寫出來則是 120 ,第一個數字 1 就是高位元組位。

生長方向為 : 從左到右 由低到高 ( 這是不變的 )


0x0001

0x0002

0x0003

0x0004

little-endian

0xcd

0xab

0x34

0x12

big-endian

0x12

0x34

0xab

0xcd

Oracle 內可以透過一張檢視查詢出各主機OS平臺的大/小位元組序,如下:

SQL>select * from v$transportable_platform

PLATFORM_ID PLATFORM_NAME ENDIAN_FORMAT

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

          1 Solaris[tm] OE (32-bit) Big

          2 Solaris[tm] OE (64-bit) Big

          7 Microsoft Windows IA (32-bit) Little

         10 Linux IA (32-bit) Little

          6 AIX-Based Systems (64-bit) Big

          3 HP-UX (64-bit) Big

          5 HP Tru64 UNIX Little

          4 HP-UX IA (64-bit) Big

         11 Linux IA (64-bit) Little

         15 HP Open VMS Little

          8 Microsoft Windows IA (64-bit) Little

          9 IBM zSeries Based Linux Big

         13 Linux x86 64-bit Little

         16 Apple Mac OS Big

         12 Microsoft Windows x86 64-bit Little

         17 Solaris Operating System (x86) Little

         18 IBM Power Based Linux Big

         20 Solaris Operating System (x86-64) Little

         19 HP IA Open VMS Little

可以看出來X86平臺cpu都是little-endian,而小型機上使用的精簡指令集架構cpu則多采用big-endian。瞭解這個對於適用bbed很重要,因為bbed裡面就是用16進位制顯示的,修改也要採用16進位制數。在不同平臺下這個修改的16進位制資料就需要根據資料庫所在平臺是little-endian或者big-endian來修改。

下面是幾個常用的:

set  設定當前的環境

show  檢視當前的環境引數,跟 sqlplus 的同名命令類似。

dump  列出指定 block 的內容

find  在指定的 block 中查詢指定的字串,結果是顯示出字串,及其偏移量 --offset ,偏移量就是在 block 中的位元組數

modify  修改指定 block 的指定偏移量的值,可以線上修改。

copy  把一個 block 的內容 copy 到另一個 block

verify  檢查當前環境是否有壞塊

sum  計算 block checksum modify 之後 block 就被標識為壞塊, current checksum reqired checksum 不一致, sum 命令可以計算出新的 checksum 並應用到當前塊。

undo  回滾當前的修改操作,如果手誤做錯了, undo 一下就 ok 了,回到原來的狀態。

revert  回滾所有之前的修改操作,意思就是  undo all

BBED> help all 可以檢視更詳細的幫助資訊

 

某客戶資料庫因為機房突然掉電導致資料庫當機。而更倒黴的是rman備份檔案也被損壞,只能恢復出資料檔案,而歸檔日誌則無法恢復。備份集恢復出來的資料因不一致導致資料庫無法正常open。

查詢各資料檔案scn結果如下

SQL> select file#,checkpoint_change#,resetlogs_change#,fuzzy,status from v$datafile_header order by 2;

        10           26271884            994063 NO  ONLINE

        16           26271884            994063 YES ONLINE

         7           26271884            994063 NO  ONLINE

        13           26271884            994063 NO  ONLINE

         5           26271884            994063 NO  ONLINE

        17           26271884            994063 YES ONLINE

         8           26271895            994063 NO  ONLINE

         6           26271895            994063 NO  ONLINE

        18           26271895            994063 YES ONLINE

         2           26271895            994063 NO  ONLINE

        14           26271895            994063 YES ONLINE

        11           26271895            994063 NO  ONLINE

         4           26271915            994063 YES ONLINE

         1           26271915            994063 NO  ONLINE

        15           26271915            994063 YES ONLINE

        12           26271915            994063 NO  ONLINE

         3           26271915            994063 NO  ONLINE

         9           26271915            994063 NO  ONLINE

SQL> select max(checkpoint_change#) from v$datafile_header;

               26271915 最大的scn

SQL> select min(checkpoint_change#) from v$datafile_header;

               26271884 最小的scn

查詢所有小於最大的scn的資料檔案資訊

SQL> select file#||' '||name||' '||bytes from v$datafile_header where checkpoint_change#<26271915;

2 E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSAUX01.DBF 880803840

5 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS05.DBF 32212254720

6 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS06.DBF 32212254720

7 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS07.DBF 32212254720

8 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS08.DBF 32212254720

10 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS10.DBF 32212254720

11 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS11.DBF 32212254720

13 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS13.DBF 32212254720

14 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS14.DBF 32212254720

16 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS16.DBF 32212254720

17 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS17.DBF 15644753920

18 E:\APP\ADMINISTRATOR\ORADATA\DATE\USERS18.DBF 15571353600

這12個資料檔案就是我們要透過bbed修改的檔案,首先在作業系統級別把這幾個檔案全部備份一遍。

因為1號檔案的scn值就是最大scn值,故可以直接以該檔案作為參考修改另外的12個檔案

SQL> select file#||' '||name||' '||bytes from v$datafile_header where file#=1;

1 E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSTEM01.DBF 933232640

 

1. 建立檔案列表引數檔案,將以上 sql 查詢結果儲存到一個文字文件中如 e:\filelist.txt

2. 建立引數檔案,該引數檔案指定了 bbed 的基本環境 e:\bbedpar.txt

blocksize=8192

listfile=e:\filelist.txt

mode=edit 

 

3 )使用引數檔案連線 bbed

 

[oracle@dg1 ~]$ bbed parfile= e:\bbedpar.tx

Password:  blockedit

BBED: Release 2.0.0.0.0 - Limited Production on Tue Jun 11 15:21:27 2015

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

************* !!! For Oracle Internal Use only !!! ***************

 

BBED> set dba 1 ,1 設定位置為1號檔案的第一個資料塊,資料檔案頭就在這裡

BBED> p kcvfh

BBED-00400: invalid blocktype (00)

正常情況下第一個資料塊就是檔案頭,但是這裡報錯應該是跟我使用的是在oracle 10g版本下編譯出來的bbed有關,用11g版本編譯出來的bbed則不會有這個問題。透過這裡發現用10g版本的bbed修改11g資料檔案,則資料檔案頭是2號塊。

BBED> set dba 1,2

BBED> p kcvfh

struct kcvfh, 340 bytes                     @0

   struct kcvfhbfh, 20 bytes                @0

      ub1 type_kcbh                         @0        0x0b

      ub1 frmt_kcbh                         @1        0xa2

      ub1 spare1_kcbh                       @2        0x00

      ub1 spare2_kcbh                       @3        0x00

      ub4 rdba_kcbh                         @4        0x00800001

      ub4 bas_kcbh                          @8        0x00000000

      ub2 wrp_kcbh                          @12       0x0000

      ub1 seq_kcbh                          @14       0x01

      ub1 flg_kcbh                          @15       0x04 (KCBHFCKV)

      ub2 chkval_kcbh                       @16       0x74bd

      ub2 spare3_kcbh                       @18       0x0000

   struct kcvfhhdr, 76 bytes                @20

 

顯示1號檔案2號資料塊offset為484開始的內容,v$data_file_header的checkpoint_change# 列值就取自這裡

BBED> dump offset 484 dba 1,2

File: E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSTEM01.DBF (1)

 Block: 2                Offsets:  484 to  995           Dba:0x00400002

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

  abe09001 00000000 55de9134 01000000 11090000 551b0000 1000f54d 02000000

……

對比顯示2號檔案2號資料塊offset為484開始的內容

BBED> dump offset 484 dba 2,2

 File: E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSAUX01.DBF (2)

 Block: 2                Offsets:  484 to  995           Dba:0x00800002

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

  97e09001 00000000 51de9134 01000000 11090000 c01a0000 1000db21 02000000

……

而根據v$datafile_header.checkpoint_change# 轉換應該是

由於X86_64架構下的windows屬於   Little endian , 故透過bbed看到的16進位制值是反向的,把上面查詢到的v$datafile_header.checkpoint_change#轉換成16進位制值則可以發現正好根dump出來的內容一致。

SQL> select to_char(26271895,'xxxxxxxx') from dual;

TO_CHAR(26271895,'XXXXXXXX')

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

  190e097  其在記憶體裡面根據   Little endian 儲存為 97e09001

SQL> select to_char(26271915,'xxxxxxxx') from dual;

 

TO_CHAR(26271915,'XXXXXXXX')

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

  190e0ab 其在記憶體裡面根據   Little endian 儲存為 abe09001

 

將2號檔案的checkpoint_change# 修改成同一號檔案一致

  BBED> modify /x abe09001 offset 484

 File: E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSAUX01.DBF (2)

 Block: 2                Offsets:  484 to  995           Dba:0x00800002

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

 abe09001 00000000 51de9134 01000000 11090000 c01a0000 1000db21 02000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 0c000c00 0c000100 00000000 00000000 00000000 02008000 d07e4101 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000

 <32 bytes per line>

BBED> verify

DBVERIFY - Verification starting

FILE = E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSAUX01.DBF

BLOCK = 1

 

Block 1 is corrupt

***

Corrupt block relative dba: 0x00800001 (file 0, block 1)

Bad header found during verification

Data in bad block -

 type: 11 format: 162 rdba: 0x00800001

 last change scn: 0x0000.00000000 seq: 0x1 flg: 0x04

 consistency value in tail: 0x00000b01

 check value in block header: 0x74bd, computed block checksum: 0x3c

 spare1: 0x0, spare2: 0x0, spare3: 0x0

***

DBVERIFY - Verification complete

 

Total Blocks Examined         : 1

Total Blocks Processed (Data) : 0

Total Blocks Failing   (Data) : 0

Total Blocks Processed (Index): 0

Total Blocks Failing   (Index): 0

Total Blocks Empty            : 0

Total Blocks Marked Corrupt   : 1 這裡就是剛剛修改過的塊,其自動被標記為損壞

Total Blocks Influx           : 0

 

BBED> sum apply  計算修改後的資料塊的checksum值,然後寫入資料塊的offset

Check value for File 2, Block 2:

current = 0x7481, required = 0x7481

再次查詢,可以看到2號檔案的checkpoint_change# 已經更正過來

SQL> select file#,checkpoint_change#,resetlogs_change#,fuzzy from v$datafile_header where file# in(1,2);

     FILE# CHECKPOINT_CHANGE# RESETLOGS_CHANGE# FUZ

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

         1           26271915            994063 NO

         2           26271915            994063 NO

按照此步驟修改餘下的11 個檔案,過程略,修改完成後

SQL> alter database open resetlogs;

alter database open resetlogs

*

1 行出現錯誤:

ORA-01194: 檔案 4 需要更多的恢復來保持一致性

ORA-01110: 資料檔案 4: 'E:\APP\ADMINISTRATOR\ORADATA\ORCL\USERS01.DBF'

 

此時檢查發現資料檔案checkpoint_change# 已經一致,但是個別檔案fuzzy yes ,這個說明資料檔案裡面的某些塊的scn 比資料檔案頭的checkpoint_change# 還大,也需要透過日誌恢復,而目前環境也不可能實現,繼續bbed 修改。

修改fuzzy ,該標記為在資料檔案頭的offset=138 處,0 表示no ,也就是修改成0 即可。

BBED> d offset 138 dba 1,2

 File: E:\APP\ADMINISTRATOR\ORADATA\ORCL\SYSTEM01.DBF (1)

 Block: 2                Offsets:  138 to  649           Dba:0x00400002

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

  0020ca0a 00005e1b 9434c90a 00000000 00000000 00000000 00000000 00000000

 

 BBED> d offset 138 dba 4,2

 File: E:\APP\ADMINISTRATOR\ORADATA\ORCL\USERS01.DBF (4)

 Block: 2                Offsets:  138 to  649           Dba:0x01000002

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

  4000c70a 00005e1b 9434c60a 00000000 00000000 00000000 00000000 00000000

 BBED> set dba 4,2

BBED> m /x 00 offset 138

BBED> sum apply

重複此步驟直到所有檔案修改完畢。最後 alter database open resetlogs 成功開啟資料庫。開啟後發現一張核心表最近一天的匯出報錯,該表基本上每時每刻都在插入資料,雖然bbed 修改後強制開啟了資料庫,但是資料的一致性實際上不可避免的要被破壞,但是至少恢復了上一次備份到斷電前一天的資料。

 

Bbed 作為oracle的內部工具,確實具備很多強大的功能,但是也並非無所不能,極端情況下可以利用它來修改資料檔案繼而開啟資料庫,單是內部的資料一致性是不能得到保障的,因此一定要提前備份資料。

 


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/23732248/viewspace-2770883/,如需轉載,請註明出處,否則將追究法律責任。

相關文章