[20250512]drop table的恢复3(包含lob类型字段).txt

[20250512]drop table的恢复3(包含lob类型字段).txt

–//作为系列测试,增加drop table的恢复(包含lob类型字段)的情况,建立表包含lob字段,每个lob字段包含2个段,1个数据段,1个其

–//索引段。当drop table时,相关数据段全部删除(包括索引段也会一起删除,不过对于恢复,索引可以重建),这样通过rowid方式恢

–//复需要建立的新表相关数据段指向原来的旧表的数据段,通过测试说明问题。

1.环境:

SCOTT@book01p> @ ver2

==============================

PORT_STRING                   : x86_64/Linux 2.4.xx

VERSION                       : 21.0.0.0.0

BANNER                        : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 – Production

BANNER_FULL                   : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 – Production

Version 21.3.0.0.0

BANNER_LEGACY                 : Oracle Database 21c Enterprise Edition Release 21.0.0.0.0 – Production

CON_ID                        : 0

PL/SQL procedure successfully completed.

2.测试环境建立:

SCOTT@book01p> create table t5 (id number ,text clob);

Table created.

SCOTT@book01p> insert into t5 select rownum,to_char(rownum)||lpad(‘x’,3964,’x’) from dual connect by level <=1e4;

10000 rows created.

SCOTT@book01p> commit ;

Commit complete.

–//记录相关数据段号:

SCOTT@book01p> @ o2 t5

SCOTT@book01p>  @pr

==============================

O_OWNER                       : SCOTT

O_OBJECT_NAME                 : T5

O_OBJECT_TYPE                 : TABLE

SEG_PART_NAME                 :

O_STATUS                      : VALID

OID                           : 128559

D_OID                         : 128559

CREATED                       : 2025-05-12 15:27:44

LAST_DDL_TIME                 : 2025-05-12 15:27:44

PL/SQL procedure successfully completed.

SCOTT@book01p> @lob scott.%128559%

SCOTT@book01p>  @pr

==============================

OWNER                         : SCOTT

TABLE_NAME                    : T5

COLUMN_NAME                   : TEXT

SEGMENT_NAME                  : SYS_LOB0000128559C00002$$

TABLESPACE_NAME               : USERS

INDEX_NAME                    : SYS_IL0000128559C00002$$

CHUNK                         : 8192

PCTVERSION                    :

RETENTION                     :

FREEPOOLS                     :

CACHE                         : NO

LOGGING                       : YES

ENCRYPT                       : NO

COMPRESSION                   : NO

DEDUPLICATION                 : NO

IN_ROW                        : YES

FORMAT                        : ENDIAN NEUTRAL

PARTITIONED                   : NO

SECUREFILE                    : YES

SEGMENT_CREATED               : YES

RETENTION_TYPE                : DEFAULT

RETENTION_VALUE               :

VALUE_BASED                   : NO

MAX_INLINE                    : 4000

PL/SQL procedure successfully completed.

SCOTT@book01p> @ o2 SYS_LOB0000128559C00002$$

SCOTT@book01p> @ pr

==============================

O_OWNER                       : SCOTT

O_OBJECT_NAME                 : SYS_LOB0000128559C00002$$

O_OBJECT_TYPE                 : LOB

SEG_PART_NAME                 :

O_STATUS                      : VALID

OID                           : 128560

D_OID                         : 128560

CREATED                       : 2025-05-12 15:27:44

LAST_DDL_TIME                 : 2025-05-12 15:27:44

PL/SQL procedure successfully completed.

SCOTT@book01p> @ o2 SYS_IL0000128559C00002$$

SCOTT@book01p> @ pr

==============================

O_OWNER                       : SCOTT

O_OBJECT_NAME                 : SYS_IL0000128559C00002$$

O_OBJECT_TYPE                 : INDEX

SEG_PART_NAME                 :

O_STATUS                      : VALID

OID                           : 128561

D_OID                         : 128561

CREATED                       : 2025-05-12 15:27:44

LAST_DDL_TIME                 : 2025-05-12 15:27:44

PL/SQL procedure successfully completed.

–//T5表的数据段号128559。字段text的lob段号128560,其索引段号128561、

SCOTT@book01p> drop table t5 purge ;

Table dropped.

SYS@book01p> @ versions obj$ OBJ#,DATAOBJ#,name s ” ” “versions_operation=’D’ and VERSIONS_STARTTIME>=’2025-05-12 15:32:10′”

VERSIONS_STARTTIME   VERSIONS_ENDTIME     VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID     V ROWID                    OBJ#   DATAOBJ# NAME

——————– ——————– —————– ————— —————- – —————— ———- ———- ——————————

2025-05-12 15:32:12.                               41543968                 09001100A51F0000 D AAAAASAABAAAI6GAAD     128560     128560 SYS_LOB0000128559C00002$$

2025-05-12 15:32:12.                               41543968                 09001100A51F0000 D AAAAASAABAAAI6GAAH     128559     128559 T5

2025-05-12 15:32:12.                               41543968                 09001100A51F0000 D AAAAASAABAAAI6GAAA     128561     128561 SYS_IL0000128559C00002$$

–//通过版本查询也能够确定删除表以及相关数据段号。

3.开始恢复:

–//不能直接建立新表在原来的表空间,为了避免建立新表的覆盖问题.可以在原表空间增加一个数据文件:

ALTER TABLESPACE USERS

  ADD DATAFILE ‘/u01/oradata/BOOK/book01p/users02.dbf’

  SIZE 100M

  AUTOEXTEND ON

  NEXT 4M

  MAXSIZE UNLIMITED;

SYS@book01p> alter database datafile ‘/u01/oradata/BOOK/book01p/users01.dbf’ offline drop;

Database altered.

–//注:因为我的测试环境没有打开归档,导致直接offline报错,加入drop没有问题,注意并非真正意思删除。

SYS@book01p> recover datafile 12;

Media recovery complete.

–//顺手先recover datafile 12;以后可以直接online。

–//然后再建立新表绕开这个覆盖问题。

–//建立的表要加入SEGMENT CREATION IMMEDIATE,不然oracle认为是空表,无法通过rowid方式读取。

SCOTT@book01p> create table t5_drop (id number ,text clob) SEGMENT CREATION IMMEDIATE ;

Table created.

SCOTT@book01p> column PARTITION_NAME noprint

SCOTT@book01p> select * from dba_extents where segment_name=’T5_DROP’;

SCOTT@book01p> @ pr

==============================

OWNER                         : SCOTT

SEGMENT_NAME                  : T5_DROP

PARTITION_NAME                :

SEGMENT_TYPE                  : TABLE

TABLESPACE_NAME               : USERS

EXTENT_ID                     : 0

FILE_ID                       : 17

BLOCK_ID                      : 128

BYTES                         : 65536

BLOCKS                        : 8

RELATIVE_FNO                  : 17

PL/SQL procedure successfully completed.

–//建立的新表使用的数据段不在数据文件号12上。

–//建立表空间TSP_AUDIT略。

–//ALTER USER SCOTT QUOTA UNLIMITED ON TSP_AUDIT;

SCOTT@book01p> create table bak_t5 tablespace TSP_AUDIT as select * from scott.t5_drop where 0=1;

Table created.

–//扫描获得信息插入的表bak_t5放在另外的表空间,避免覆盖原来的数据文件信息。

–//修改相关段号:

SYS@book01p> @ versions obj$ OBJ#,DATAOBJ#,name s ” ” “versions_operation=’I’ and VERSIONS_STARTTIME>=’2025-05-12 15:32:10′”

VERSIONS_STARTTIME   VERSIONS_ENDTIME     VERSIONS_STARTSCN VERSIONS_ENDSCN VERSIONS_XID     V ROWID                    OBJ#   DATAOBJ# NAME

——————– ——————– —————– ————— —————- – —————— ———- ———- ——————————

2025-05-12 15:39:44.                               41545595                 04000800821F0000 I AAAAASAABAAAI6GAAD     128563     128563 SYS_LOB0000128562C00002$$

2025-05-12 15:39:44.                               41545595                 04000800821F0000 I AAAAASAABAAAI6GAAG     128562     128562 T5_DROP

2025-05-12 15:39:44.                               41545595                 04000800821F0000 I AAAAASAABAAAI6GAAA     128564     128564 SYS_IL0000128562C00002$$

2025-05-12 15:42:45.                               41548664                 06000400471F0000 I AAAAASAABAAAI6GAAL     128566     128566 SYS_LOB0000128565C00002$$

2025-05-12 15:42:45.                               41548664                 06000400471F0000 I AAAAASAABAAAI6GAAH     128565     128565 BAK_T5

2025-05-12 15:42:45.                               41548664                 06000400471F0000 I AAAAASAABAAAI6GAAK     128567     128567 SYS_IL0000128565C00002$$

6 rows selected.

–//建立新表以及lob以及索引段号分别是128562,128563,128564

–//修改指向旧表T5.

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128562) set DATAOBJ#=128559;

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128563) set DATAOBJ#=128560;

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128564) set DATAOBJ#=128561;

commit ;

SYS@book01p> alter system flush shared_pool;

System altered.

–//扫描数据文件确定数据段号。

$ . finddoid.sh 12 128 32640 128559

data_object_id 128559 max_row = 153

–//该脚本顺便确定数据块的最大行记录153条。

–//建立2个文件:

$ paste scan_128559.txt scan_row_128559.txt | head -4

12,171  151

12,172  151

12,173  151

12,174  153

$ sed ‘s/^/insert into scanblock values (/;s/$/);/’ scan_128559.txt | head -3

insert into scanblock values (12,171);

insert into scanblock values (12,172);

insert into scanblock values (12,173);

$ sed ‘s/^/insert into scanblock values (/;s/$/);/’ scan_128559.txt >| xy.txt

SYS@book01p> create table scott.scanblock ( file_id number,block_id number  )  tablespace TSP_AUDIT;

Table created.

–//注意建立的新表一定不能使用原来的表空间,避免覆盖。

–//执行xy.txt脚本,注意提交。

SYS@book01p> set timing on

SYS@book01p> @ txt/truncT.txt SCOTT T5_DROP SCOTT BAK_T5 152

PL/SQL procedure successfully completed.

Elapsed: 00:00:19.85

SYS@book01p> set timing off

–//参数5=152,行号从0开始计数。

–//补充应该可以再改进减少扫描范围,另外写一篇blog。

SCOTT@book01p> select count(*) from bak_t5;

  COUNT(*)

———-

     10000

–//完全恢复。

4.收尾还原:

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128562) set DATAOBJ#=128562;

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128563) set DATAOBJ#=128563;

update (select OBJ#,DATAOBJ#,OWNER#,NAME from obj$ where obj#=128564) set DATAOBJ#=128564;

commit ;

5.附上相关执行脚本:

$ cat finddoid.sh

#! /bin/bash

# argv1=file_number argv2=begin_block argvs3=end_block argv4=data_object_id

file_number=$1

begin_block=$2

end_block=$3

data_object_id=$4

# scan begin_block to end_block,define search scope.

/bin/rm scan_${data_object_id}.txt 2>/dev/null

#seq  -f “%-1.0f” $begin_block $end_block | xargs -IQ echo -e “host echo $file_number,Q \np /d dba $file_number,Q ktbbh.ktbbhsid.ktbbhod1” | \

#rlbbed | grep “^BBED” | egrep “$file_number,|ub4 ktbbhod1″ | awk ‘{print $NF}’ | paste -d” ” – – | awk -v a=$data_object_id ‘$2==a {print $1}’ >| scan_${data_object_id}.txt

seq  -f “%-1.0f” $begin_block $end_block | xargs -IQ echo -e “host echo -n $file_number,Q \np /d dba $file_number,Q ktbbh.ktbbhsid.ktbbhod1” | \

rlbbed | grep -B1 –no-group-separator “ub4 ktbbhod1″ | awk ‘{print $NF}’ | paste -d” ” – – | awk -v a=$data_object_id ‘$2==a {print $1}’ >| scan_${data_object_id}.txt

# scan begin_block to end_block,obtain max row.

/bin/rm scan_row_${data_object_id}.txt 2>/dev/null

cat scan_${data_object_id}.txt | xargs -IQ echo p dba Q kdbt[0].kdbtnrow | rlbbed | grep kdbtnrow | awk ‘{print $NF}’ >| scan_row_${data_object_id}.txt

max_row=$(sort -nr scan_row_${data_object_id}.txt | head -1)

echo data_object_id $data_object_id  max_row = $max_row

$ cat txt/truncT.txt

DECLARE

   v_fno          NUMBER;

   v_s_bno        NUMBER;

   v_e_bno        NUMBER;

   v_rowid        ROWID;

   v_owner        VARCHAR2 (100) := ‘&&1’;

   v_table        VARCHAR2 (100) := ‘&&2’;

   v_o_owner      VARCHAR2 (100) := ‘&&3’;

   v_o_table      VARCHAR2 (100) := ‘&&4’;

   v_dataobj      NUMBER;

   v_sql          VARCHAR2 (4000);

   v_tablespace   VARCHAR2 (100);

   nrows          NUMBER;

BEGIN

   nrows := 0;

   SELECT data_object_id

     INTO v_dataobj

     FROM dba_objects

    WHERE owner = v_owner AND object_name = v_table;

   SELECT tablespace_name

     INTO v_tablespace

     FROM dba_tables

    WHERE owner = v_owner AND table_name = v_table;

—   FOR i

—      IN (SELECT relative_fno, block_id, blocks FROM dba_extents WHERE owner = v_owner AND segment_name = v_table AND extent_id = 0

—          UNION ALL

—          SELECT relative_fno, block_id, blocks FROM dba_free_space WHERE tablespace_name = v_tablespace

—          UNION ALL

—          SELECT relative_fno, block_id, blocks

—            FROM (SELECT relative_fno

—                        ,block_id

—                        ,blocks

—                        ,ROW_NUMBER () OVER (PARTITION BY owner, segment_name, partition_name ORDER BY extent_id DESC)

—                            rn

—                    FROM dba_extents

—                   WHERE tablespace_name = v_tablespace AND extent_id > 0)

—           WHERE rn = 1)

   for i in (select file_id relative_fno,block_id, 1 blocks  from scott.scanblock)

   LOOP

      v_fno := i.relative_fno;

      v_s_bno := i.block_id;

      v_e_bno := i.block_id + i.blocks – 1;

      –v_e_bno:=i.block_id+1-1; –//using scanblock method

      FOR j IN v_s_bno .. v_e_bno

      LOOP

         BEGIN

            FOR x IN 0 .. &&5

            LOOP

               v_rowid := DBMS_ROWID.rowid_create ( 1 ,v_dataobj ,v_fno ,j ,x);

               v_sql :=

                     ‘insert into ‘

                  || v_o_owner

                  || ‘.’

                  || v_o_table

                  || ‘ select * from ‘

                  || v_owner

                  || ‘.’

                  || v_table

                  || ‘ where rowid=:1’;

               EXECUTE IMMEDIATE v_sql USING v_rowid;

               IF SQL%ROWCOUNT = 1

               THEN

                  nrows := nrows + 1;

               END IF;

               IF (MOD (nrows, 10000) = 0)

               THEN

                  COMMIT;

               END IF;

            END LOOP;

         EXCEPTION

            WHEN OTHERS

            THEN

               NULL;

         END;

         COMMIT;

      END LOOP;

   END LOOP;

END;

/

来源链接:https://www.cnblogs.com/lfree/p/18874856

© 版权声明
THE END
支持一下吧
点赞6 分享
评论 抢沙发
头像
请文明发言!
提交
头像

昵称

取消
昵称表情代码快捷回复

    暂无评论内容