DBA实验手册第3讲 运用bbed工具恢复delete误删除的数据

2024年 6月 7日 21.7k 0

     --(南宋)陆游《冬夜读书示子聿》

 前       言 

01

当面试官问你,Oracle数据库的表被执行了delete操作并已提交,如何找回数据呢?常规的修复方法包括闪回表、impdp单表导入、rman单表恢复,除了这些方法之外,还可以考虑使用BBED工具找回数据。今天我想跟大家先分享下如何运用bbed工具恢复delete误删除的数据。想深入学习bbed工具的朋友,一定要动手多做实验!

当Oracle数据库执行delete语句后,表中数据实际上并没有被删除,而是将行标记为已删除,表示数据块可以重用。因此,在数据块没有被覆盖之前,将数据块上的标志位的已删除标记去掉,就可以找回数据了。

 往期文章推荐 

02

1、DBA实验手册第1讲 运用bbed工具和SQL语句学习bootstrap$表存储信息

2、DBA实验手册第2讲 运用bbed工具恢复bootstrap$表数据

欢迎关注公众号!

 数据块简介 

03

在Oracle数据库中,块是存储数据的最小单位,一个块通常大小为8KB。块是Oracle进行I/O操作的基本单位,它用于存储表数据、索引、回滚段数据、临时数据等。数据库中的所有数据都存储在块中,包括表的行数据、索引键值和数据字典信息等。每个数据块的块头结构都是固定的。所有的数据块都包含相同的头结构----kcbh。行状态存储在每行的行标头中,该行标头占用每行的前几个字节。行标头由行标记、锁字节(ITL条目)和列计数组成。第一个Row标志是一个单字节,它保存一个显示行状态的位掩码。位掩码解码如下:

DBA实验手册第3讲 运用bbed工具恢复delete误删除的数据-1

因此行标头(数据块dump文件中的“--H-FL--”对应上面表格的8列信息)=Head of row picec + First data picec + Last data picec = 32+8+4 = 44 转换为16进制 0x2c。当数据被删除后,行标头+(Deleted 16) =32+16+8+4=60 转换为16进制 0x3c。

    SQL> select to_char(44,'xxxxxxxx') as hex1,
    to_char(60,'xxxxxxxx') as hex2 from dual;
    HEX1 HEX2
    --------- ---------
    2c 3c

    因此,当数据未被覆盖时,修改行标头0x3c为0x2c即可恢复。

    上面的内容你看明白了没有,如果没理解,可以再认真读一遍,然后再阅读下面的内容。

     实验环境准备 

    04

    数据库版本:Oracle 12.1.0.2.0 单机版

    BBED版本:BBED 2.0.0.0.0

    操作系统:Red Hat Enterprise Linux Server 6.5

    若想获取实验环境相关的软件包、文档资料以及批量恢复脚本,可以查看文章的附件部分。

    1、创建测试表空间和测试用户

      SQL> select file_name from dba_data_FILES;
      SQL> create tablespace mytbs datafile '/u01/app/oracle/oradata/PROD4/mytbs.dbf' size 50m;
      SQL> create user myuser identified by oracle default tablespace mytbs;
      SQL> grant resource,connect, select any dictionary to myuser;
      SQL> alter user myuser quota unlimited on mytbs;

      2、创建测试表与数据,这边只模拟2行记录,这样的话后面dump出来的日志会简短些。

        SQL> create table mytable (id number,name varchar2(10));
        SQL> insert into mytable values(100,'dba1');
        SQL> insert into mytable values(200,'dba2');

        3、刷新缓存,让脏数据落盘

          SQL> alter system flush buffer_cache;
          System altered.

           第1次dump数据块 

          05

          1、查看表数据分布情况

            1 数据文件号(dba_objects)
            SQL> select object_id from dba_objects
            where object_name = 'MYTABLE' and owner = 'MYUSER';
            OBJECT_ID
            ----------
            93996
            2、数据分布在2号文件的133数据块
            SQL> select distinct dbms_rowid.rowid_relative_fno(rowid) rfno,
            dbms_rowid.rowid_block_number(rowid) blocknum
            from myuser.mytable order by 2;
            RFNO BLOCKNUM
            ---------- ----------
            2 133
            3、表存储在2号文件的第1个区,从128号数据块开始,占用8个块,共65536字节(8k*8个)
            SQL> select EXTENT_ID,FILE_ID,BLOCK_ID,BYTES,BLOCKS
            from dba_extents where segment_name='MYTABLE';
            EXTENT_ID FILE_ID BLOCK_ID BYTES BLOCKS
            ---------- ---------- ---------- ---------- ----------
            0 2 128 65536 8
            4、数据段基本信息
            SQL> col segment_name for a15
            SQL> col tablespace_name for a15
            SQL> select segment_name,tablespace_name,header_file,header_block
            from dba_segments where segment_name='MYTABLE';
            SEGMENT_NAME TABLESPACE_NAME HEADER_FILE HEADER_BLOCK
            --------------- --------------- ----------- ------------
            MYTABLE MYTBS 2 130

            2、数据块转储

            转储MYTABLE表的133数据块,查看删除之前的内容。

              1、转储命令
              SQL> alter system dump datafile 2 block 133;
              System altered.
              SQL> select value from v$diag_info where name ='Default Trace File';
              VALUE
              --------------------------------------------------------------------------------
              /u01/app/oracle/diag/rdbms/prod4/PROD4/trace/PROD4_ora_85254.trc


              2、133数据块转储内容
              没有执行alter system flush buffer_cache,即脏数据未落盘
              Start dump data blocks tsn: 9 file#:2 minblk 133 maxblk 133
              Block dump from cache:【dump出缓存cache的内容】
              Dump of buffer cache at level 4 for pdb=0 tsn=9 rdba=8388741
              BH (0x77ff6bd8) file#: 2 rdba: 0x00800085 (2/133) class: 1 ba: 0x77f48000
              set: 5 pool: 3 bsz: 8192 bsi: 0 sflg: 0 pwc: 0,0
              dbwrid: 0 obj: 93996 objn: 93996 tsn: [0/9] afn: 2 hint: f
              hash: [0x7cbe8e28,0x7cbe8e28] lru: [0x77ff6e00,0x77ff6b80]
              obj-flags: object_ckpt_list
              ckptq: [0x77ff6a98,0x77ff6d18] fileq: [0x77ff6aa8,0x77ff6d28]
              objq: [0x77ff6e28,0x77ff6ba8] objaq: [0x77ff6e38,0x77ff6bb8]
              st: XCURRENT md: NULL fpin: 'ktspbwh2: ktspfmdb' fscn: 0x0.3d4778 tch: 4
              flags: buffer_dirty
              LRBA: [0x2.1f1b.0] LSCN: [0x0.3d4778] HSCN: [0x0.3d477c] HSUB: [1]
              Block dump from disk:【dump出磁盘的内容】
              Encrypted block content will not be dumped. Dumping header only.
              buffer tsn: 9 rdba: 0x00000085 (0/133)
              scn: 0x0.0 seq: 0x01 flg: 0x05 tail: 0x00000001
              frmt: 0x02 chkval: 0xa785 type: 0x00=unknown
              Hex dump of initial block header 1 = INITIAL
              Dump of memory from 0x00007FA34753E200 to 0x00007FA34753E214
              7FA34753E200 0000A200 00000085 00000000 05010000 [................]
              7FA34753E210 0000A785 [....]
              End dump data blocks tsn: 9 file#: 2 minblk 133 maxblk 133


              3、133数据块转储内容
              执行alter system flush buffer_cache,即脏数据已落盘
              Start dump data blocks tsn: 9 file#:2 minblk 133 maxblk 133
              Block dump from cache:【dump出缓存cache的内容】
              Dump of buffer cache at level 4 for pdb=0 tsn=9 rdba=8388741
              BH (0x77ff6bd8) file#: 2 rdba: 0x00800085 (2/133) class: 1 ba: 0x77f48000
              set: 5 pool: 3 bsz: 8192 bsi: 0 sflg: 0 pwc: 0,0
              dbwrid: 0 obj: 93996 objn: 93996 tsn: [0/9] afn: 2 hint: f
              hash: [0x7cbe8e28,0x7cbe8e28] lru: [0x753dcc80,0x743da840]
              lru-flags: on_auxiliary_list
              ckptq: [NULL] fileq: [NULL]
              objq: [NULL] objaq: [NULL]
              st: FREE md: NULL fpin: 'ktspbwh2: ktspfmdb' fscn: 0x0.3d4778 tch: 0 lfb: 33
              flags:
              Block dump from disk:【dump出磁盘的内容】
              buffer tsn: 9 rdba: 0x00800085 (2/133)
              scn: 0x0.3d477c seq: 0x01 flg: 0x06 tail: 0x477c0601
              frmt: 0x02 chkval: 0xbd31 type: 0x06=trans data
              Hex dump of block: st=0, typ_found=1
              Dump of memory from 0x00007FD4F7ECA200 to 0x00007FD4F7ECC200
              7FD4F7ECA200 0000A206 00800085 003D477C 06010000 [........|G=.....]
              7FD4F7ECA210 0000BD31 00000001 00016F2C 003D4778 [1.......,o..xG=.]
              7FD4F7ECA220 00000000 00320002 00800080 00030007 [......2.........]
              7FD4F7ECA230 000006C4 0100092A 00040123 00002002 [....*...#.... ..]
              7FD4F7ECA240 003D477C 00000000 00000000 00000000 [|G=.............]
              7FD4F7ECA250 00000000 00000000 00000000 00000000 [................]
              7FD4F7ECA260 00000000 00020100 0016FFFF 1F6C1F82 [..............l.]
              7FD4F7ECA270 00001F6C 1F8D0002 00001F82 00000000 [l...............]
              7FD4F7ECA280 00000000 00000000 00000000 00000000 [................]
              Repeat 501 times
              7FD4F7ECC1E0 00000000 012C0000 03C20202 61626404 [......,......dba]
              7FD4F7ECC1F0 02012C32 0402C202 31616264 477C0601 [2,......dba1..|G]
              Block header dump: 0x00800085
              Object id on Block? Y
              seg/obj: 0x16f2c csc: 0x00.3d4778 itc: 2 flg: E typ: 1 - DATA
              brn: 0 bdba: 0x800080 ver: 0x01 opc: 0
              inc: 0 exflg: 0


              Itl Xid Uba Flag Lck Scn/Fsc
              0x01 0x0007.003.000006c4 0x0100092a.0123.04 --U- 2 fsc 0x0000.003d477c
              0x02 0x0000.000.00000000 0x00000000.0000.00 ---- 0 fsc 0x0000.00000000
              bdba: 0x00800085
              data_block_dump,data header at 0x7fd4f7eca264
              ===============
              tsiz: 0x1f98
              hsiz: 0x16
              pbl: 0x7fd4f7eca264
              76543210
              flag=--------
              ntab=1
              nrow=2 【表示有2行数据】
              frre=-1
              fsbo=0x16
              fseo=0x1f82
              avsp=0x1f6c
              tosp=0x1f6c
              0xe:pti[0] nrow=2 offs=0
              0x12:pri[0] offs=0x1f8d
              0x14:pri[1] offs=0x1f82
              block_row_dump: 【每行记录信息】
              tab 0, row 0, @0x1f8d 【第1行记录】
              tl: 11 fb: --H-FL-- lb: 0x1 cc: 2
              col 0: [ 2] c2 02
              col 1: [ 4] 64 62 61 31
              tab 0, row 1, @0x1f82 【第2行记录】
              tl: 11 fb: --H-FL-- lb: 0x1 cc: 2
              col 0: [ 2] c2 03
              col 1: [ 4] 64 62 61 32
              end_of_block_dump
              End dump data blocks tsn: 9 file#: 2 minblk 133 maxblk 133

              3、通过bbed查看数据文件结构体信息

                BBED> set dba 2,133   【定位到2,133数据块】
                DBA 0x00800085 (8388741 2,133)


                BBED> p
                kcbh.type_kcbh
                --------------
                ub1 type_kcbh @0 0x06


                BBED> map
                File: /u01/app/oracle/oradata/PROD4/mytbs.dbf (2)
                Block: 133 Dba:0x00800085
                ------------------------------------------------------------
                 KTB Data Block (Table/Cluster)
                 struct kcbh, 20 bytes                      @0      【块头】    
                 struct ktbbh, 72 bytes                     @20     【事务层头结构】 
                 struct kdbh, 14 bytes                      @100    【事务型数据(data类型)的数据层头结构】 
                 struct kdbt[1], 4 bytes                    @114    【数据层表索引】
                 sb2 kdbr[2]                                @118    【数据层行索引】 
                 ub1 freespace[8044]                        @122    【空闲空间】 
                 ub1 rowdata[22]                            @8166   【数据存放内容】
                ub4 tailchk @8188 【尾块】


                BBED> p kdbr 【行索引,行索引也是一个数组,定义了该块中包含的所有行数据的位置。行索引的插槽由2个字节组成】
                sb2 kdbr[0] @118 8077
                sb2 kdbr[1] @120 8066


                BBED> p *kdbr[0] 【查看行索引】
                rowdata[11]
                -----------
                ub1 rowdata[11] @8177 0x2c 【0x2c表示标志位是--H-FL--(32+8+4 = 44转换成16进制为2c)】


                BBED> x rnc *kdbr[0]
                rowdata[11] @8177
                -----------
                flag@8177: 0x2c (KDRHFL, KDRHFF, KDRHFH)
                lock@8178: 0x01
                cols@8179: 2


                col 0[2] @8180: 100 【第1条记录 第1列数据】
                col 1[4] @8183: dba1 【第1条记录 第2列数据】


                BBED> p *kdbr[1]
                rowdata[0]
                ----------
                ub1 rowdata[0] @8166 0x2c 【0x2c表示标志位是--H-FL--(32+8+4 = 44转换成16进制为2c)】


                BBED> x rnc *kdbr[1]
                rowdata[0] @8166
                ----------
                flag@8166: 0x2c (KDRHFL, KDRHFF, KDRHFH)
                lock@8167: 0x01
                cols@8168: 2
                col 0[2] @8169: 200 【第2条记录 第1列数据】
                col 1[4] @8172: dba2 【第2条记录 第2列数据】

                 模拟数据丢失 

                06

                删除测试表记录,模拟delete误删除操作

                  SQL> delete from myuser.mytable;
                  2 rows deleted.


                  SQL> commit;
                  Commit complete.


                  SQL> alter system flush buffer_cache;
                  System altered.

                   第2次dump数据块 

                  07

                  1、再次转储数据块,查看数据删除后的信息

                    1、转储数据块操作
                    SQL> alter system dump datafile 2 block 133;
                    System altered.


                    SQL> select value from v$diag_info 
                    where name ='Default Trace File';
                    VALUE
                    --------------------------------------------------------------------------------
                    /u01/app/oracle/diag/rdbms/prod4/PROD4/trace/PROD4_ora_120104.trc

                    2、具体的trace日志内容

                      *** 2024-06-06 23:40:52.588
                      Start dump data blocks tsn: 9 file#:2 minblk 133 maxblk 133
                      Block dump from cache:
                      Dump of buffer cache at level 4 for pdb=0 tsn=9 rdba=8388741
                      BH (0x7a7f6f98) file#: 2 rdba: 0x00800085 (2/133) class: 1 ba: 0x7a74e000
                      set: 5 pool: 3 bsz: 8192 bsi: 0 sflg: 0 pwc: 0,0
                      dbwrid: 0 obj: 93996 objn: 93996 tsn: [0/9] afn: 2 hint: f
                      hash: [0x7cbe8e28,0x7cbe8e28] lru: [0x74be1b40,0x783d6600]
                      lru-flags: moved_to_tail on_auxiliary_list
                      ckptq: [NULL] fileq: [NULL]
                      objq: [NULL] objaq: [NULL]
                      st: FREE md: NULL fpin: 'kdswh01: kdstgr' fscn: 0x0.0 tch: 0 lfb: 33
                      flags:
                      Block dump from disk:
                      buffer tsn: 9 rdba: 0x00800085 (2/133)
                      scn: 0x0.3dc57b seq: 0x01 flg: 0x06 tail: 0xc57b0601
                      frmt: 0x02 chkval: 0x706c type: 0x06=trans data
                      Hex dump of block: st=0, typ_found=1
                      Dump of memory from 0x00007F717BCC2200 to 0x00007F717BCC4200
                      7F717BCC2200 0000A206 00800085 003DC57B 06010000 [........{.=.....]
                      7F717BCC2210 0000706C 00000001 00016F2C 003DC57A [lp......,o..z.=.]
                      7F717BCC2220 00000000 00320002 00800080 00030007 [......2.........]
                      7F717BCC2230 000006C4 0100092A 00040123 00008000 [....*...#.......]
                      7F717BCC2240 003D477C 001A0009 0000081B 010011E8 [|G=.............]
                      7F717BCC2250 002C013A 00122002 003DC57B 00000000 [:.,.. ..{.=.....]
                      7F717BCC2260 00000000 00020100 0016FFFF 1F6C1F82 [..............l.]
                      7F717BCC2270 00001F82 1F8D0002 00001F82 00000000 [................]
                      7F717BCC2280 00000000 00000000 00000000 00000000 [................]
                      Repeat 501 times
                      7F717BCC41E0 00000000 023C0000 03C20202 61626404 [...... set offset 8177 【从上述日志文件可知,第1行的偏移位置为8177】
                      OFFSET 8177


                      BBED> d v
                      File: u01/app/oracle/oradata/PROD4/mytbs.dbf (2)
                      Block: 133 Offsets: 8177 to 8191 Dba:0x00800085
                      -------------------------------------------------------
                      3c020202 c2020464 62613101 067bc5 l m x 2c offset 8177
                      File: u01/app/oracle/oradata/PROD4/mytbs.dbf (2)
                      Block: 133 Offsets: 8177 to 8191 Dba:0x00800085
                      ------------------------------------------------------------------------
                      2c020202 c2020464 62613101 067bc5





                      BBED> set offset 8166 【从上述日志文件可知,第2行的偏移位置为8166】
                      OFFSET 8166


                      BBED> d /v
                      File: /u01/app/oracle/oradata/PROD4/mytbs.dbf (2)
                      Block: 133 Offsets: 8166 to 8191 Dba:0x00800085
                      -------------------------------------------------------
                      3c020202 c2030464 6261322c 020202c2 l m /x 2c offset 8166
                      File: /u01/app/oracle/oradata/PROD4/mytbs.dbf (2)
                      Block: 133 Offsets: 8166 to 8191 Dba:0x00800085
                      ------------------------------------------------------------------------
                      2c020202 c2030464 6261322c 020202c2 02046462 61310106 7bc5





                      BBED> sum apply;
                      Check value for File 2, Block 133:
                      current = 0x607c, required = 0x607c

                      2、验证数据已恢复出来

                        SQL> alter system flush buffer_cache;
                        System altered.


                        SQL> select * from myuser.mytable;
                        ID NAME
                        ---------- ----------
                        100 dba1
                        200 dba2

                         实验总结 

                        10

                        当Oracle数据库执行delete语句后,表中数据实际上并没有被删除,而是将行标记为已删除,表示数据块可以重用。因此,在数据块没有被覆盖之前,将数据块上的标志位的已删除标记去掉,就可以找回数据了。通过对比数据块删除数据前、后两次转储信息,可以知道块中行存在数据时标志位是fb: --H-FL--,行数据被删除后标志位变成fb: --HDFL--,换行成16进制,标志位改成0x2c表示存在数据。通过上述实验,我们在数据未被覆盖时,修改行标头0x3c为0x2c,然后把数据恢复出来。bbed恢复过程总结如下:

                        相关文章

                        众所周知的原因安装PMM2
                        唯一上榜!OceanBase入选 2023“科创中国”先导技术榜!
                        MySQL 删除数据表
                        利用 MySQL 克隆插件搭建主从
                        MySQL索引前缀长度超限怎么办?这种方法帮你搞定
                        SQL优化

                        发布评论