Oracle之bootstrap$数据字典对象损坏重建步骤随笔

oracle数据库热启动流程
1、oracle默认找system表空间file# 1文件的@96字节处,
该位置记录的rdba地址指向bootstrap$表

2、bootstrap$表记录着oracle必须的数据字典ddl语句

3、bootstrap$表按照line 列、sql_text ddl内容进行数据字典内存表的创建

4、line 列再根据obj# 列找到该内存对象在磁盘的数据存储并加载


当bootstrap$表内某个核心表的index损坏时,我们可以通过复制创建
新的bootstrap$img,损坏对象表及表索引的img对象,将img对象的obj#替换到
bootstra$img中,这样相当于在创建损坏对象的img时,数据创建了一份,
索引变相的重建了一次,让表和索引数据对应,将来新的bootstrap$img加载
新的磁盘img对象数据;同时为了数据字典的数据一致性,还必须将obj$表中
损坏对象的obj#指向新的img对象的obj#

 

 

重建bootstrap$记录的前60对象步骤

1、创建bootstrap$ 及损坏对象的镜像对象

--创建 bootstrap$ 的镜像表 BOOTSTRAP$IMG

  CREATE TABLE "SYS"."BOOTSTRAP$IMG"
   (    "LINE#" NUMBER,
        "OBJ#" NUMBER,
        "SQL_TEXT" VARCHAR2(4000)
   );


--创建 bootstrap$ 的第二张镜像表 BOOTSTRAP$TMPSTR

  CREATE TABLE "SYS"."BOOTSTRAP$TMPSTR"
   (    "LINE#" NUMBER,
        "OBJ#" NUMBER,
        "SQL_TEXT" VARCHAR2(4000)
   );

 


--创建 CON$ 的镜像表及索引 CON$IMG I_CON1_IMG I_CON2_IMG

  CREATE TABLE "SYS"."CON$IMG"
   (    "OWNER#" NUMBER,
        "NAME" VARCHAR2(128),
        "CON#" NUMBER,
        "SPARE1" NUMBER,
        "SPARE2" NUMBER,
        "SPARE3" NUMBER,
        "SPARE4" VARCHAR2(1000),
        "SPARE5" VARCHAR2(1000),
        "SPARE6" DATE
   );




  CREATE UNIQUE INDEX "SYS"."I_CON1_IMG" ON "SYS"."CON$IMG" ("OWNER#", "NAME");


  CREATE UNIQUE INDEX "SYS"."I_CON2_IMG" ON "SYS"."CON$IMG" ("CON#");

 

2、生成新的bootstrap中的sql_text(obj#、file#、block#)


原bootstrap$内,con$ i_con1 i_con2 bootstrap$定义(建议查询出来备份)

CREATE TABLE CON$("OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(128) NOT NULL,"CON#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 28 EXTENTS (FILE 1 BLOCK 288))
CREATE UNIQUE INDEX I_CON1 ON CON$(OWNER#,NAME) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 51 EXTENTS (FILE 1 BLOCK 456))
CREATE UNIQUE INDEX I_CON2 ON CON$(CON#) PCTFREE 10 INITRANS 2 MAXTRANS 255 STORAGE (  INITIAL 64K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 52 EXTENTS (FILE 1 BLOCK 464))
CREATE TABLE BOOTSTRAP$("LINE#" NUMBER NOT NULL,"OBJ#" NUMBER NOT NULL,"SQL_TEXT" VARCHAR2(4000) NOT NULL) PCTFREE 10 PCTUSED 40 INITRANS 1 MAXTRANS 255 STORAGE (  INITIAL 56K NEXT 1024K MINEXTENTS 1 MAXEXTENTS 2147483645 PCTINCREASE 0 OBJNO 59 EXTENTS (FILE 1 BLOCK 520))


--生成需要替换对象的新的sql_text

declare
    pl_objtxt       varchar2(4000);   /* bootstrap$.sql_text for the new obj */
    pl_obj_num      number;           /* obj# of the new obj */
    pl_line_num number;               /* line# in bootstrap$ for the new obj */

    /* Get Obj Number in OBJ$
       Given the obj name and namespace, return the obj# in obj$.
    */
    function get_obj_num(pl_objname varchar2, pl_nmspc number) return number
    is
      pl_obn number;
    begin
      select obj# into pl_obn from sys.obj$
        where owner#=0 and name=pl_objname and namespace=pl_nmspc;

      return pl_obn;
    end;

    /* Get Line Number in bootstrap$
       Given the obj name and namespace, returns the line# in boostrap$. If the
       obj doesn't exists, then return null.
    */
    function get_line_num(pl_objname varchar2, pl_nmspc number) return number
    is
      pl_bln number;
    begin
      select b.line# into pl_bln
      from sys.bootstrap$ b, sys.obj$ o
      where o.owner#    = 0
        and o.name      = pl_objname
        and o.obj#      = b.obj#
        and o.namespace = pl_nmspc;

      return pl_bln;
    exception
      when NO_DATA_FOUND then
      return NULL;
    end;

    /* Storage text generation
       The bootstrap$ sql_text requires the DDL to provide the storage
       parameters. The following function will generate the storage
       parameter for table creation and index creation, given the obj# as input.
    */
    -- generate storage parameter
    --   it requires some info from tab$/ind$, seg$, ts$
    function gen_storage(pl_objnum number, pl_objtype varchar2) return varchar2
    is
      pl_text        varchar2(4000);
      pl_pctf        number;
      pl_pctused     number;
      pl_initrans    number;
      pl_maxtrans    number;
      pl_file_num    number;
      pl_block_num   number;
      pl_ts_num      number;
      pl_tab_num     number;
      pl_initial     number;
      pl_next        number;
      pl_minext      number;
      pl_maxext      number;
      pl_pctinc      number;
      pl_block_size  number;
    begin
      if (pl_objtype = 'TABLE') then
        -- info from tab$
        select pctfree$, pctused$, initrans, maxtrans, file#, block#, ts#
          into pl_pctf,     pl_pctused,   pl_initrans, pl_maxtrans,
               pl_file_num, pl_block_num, pl_ts_num
        from sys.tab$
        where obj# = pl_objnum;
      elsif (pl_objtype = 'CLUSTER TABLE') then
        select tab#
          into pl_tab_num
        from sys.tab$
        where obj# = pl_objnum;
      elsif (pl_objtype = 'INDEX') then
        -- info from ind$
        select pctfree$, initrans, maxtrans, file#, block#, ts#
          into pl_pctf,     pl_initrans,  pl_maxtrans,
               pl_file_num, pl_block_num, pl_ts_num
        from ind$ where obj# = pl_objnum;
      end if;

      if (pl_objtype != 'CLUSTER TABLE') then
        -- info from seg$
        select iniexts,    minexts,   maxexts,   extsize, extpct
          into pl_initial, pl_minext, pl_maxext, pl_next, pl_pctinc
        from sys.seg$
        where file#  = pl_file_num
          and block# = pl_block_num
          and ts#    = pl_ts_num;

        -- info from ts$
        select blocksize into pl_block_size from sys.ts$ where ts# = pl_ts_num;
        pl_initial := pl_initial * pl_block_size;
        pl_next    := pl_next    * pl_block_size;
      end if;

      if (pl_objtype = 'TABLE') then
        -- generate the table storage text
        pl_text := ' PCTFREE '  || pl_pctf     || ' PCTUSED ' || pl_pctused  ||
                   ' INITRANS ' || pl_initrans || ' MAXTRANS '|| pl_maxtrans ||
                   ' STORAGE (  INITIAL '     || pl_initial ||
                              ' NEXT '        || pl_next    ||
                              ' MINEXTENTS '  || pl_minext  ||
                              ' MAXEXTENTS '  || pl_maxext  ||
                              ' PCTINCREASE ' || pl_pctinc  ||
                              ' OBJNO '       || pl_obj_num ||
                              ' EXTENTS (FILE '  || pl_file_num  ||
                                       ' BLOCK ' || pl_block_num ||'))';
      elsif (pl_objtype = 'CLUSTER TABLE') then
        pl_text := ' STORAGE (  OBJNO '|| pl_obj_num ||
                              ' TABNO '|| pl_tab_num ||
                   ') CLUSTER C_USER#(USER#)';
      elsif (pl_objtype = 'INDEX') then
        -- generate the index storage text
        pl_text := ' PCTFREE '  || pl_pctf     ||
                   ' INITRANS ' || pl_initrans ||
                   ' MAXTRANS ' || pl_maxtrans ||
                   ' STORAGE (  INITIAL '     || pl_initial ||
                              ' NEXT '        || pl_next    ||
                              ' MINEXTENTS '  || pl_minext  ||
                              ' MAXEXTENTS '  || pl_maxext  ||
                              ' PCTINCREASE ' || pl_pctinc  ||
                              ' OBJNO '       || pl_obj_num ||
                              ' EXTENTS (FILE '  || pl_file_num  ||
                                       ' BLOCK ' || pl_block_num ||'))';
      end if;

      return pl_text;
    end;

  begin
    /* Create the bootstrap sql text for CON$  */
    pl_obj_num  := get_obj_num('CON$IMG', 1);
    pl_line_num := get_line_num('CON$', 1);
    pl_objtxt := 'CREATE TABLE CON$("OWNER#" NUMBER NOT NULL,"NAME" VARCHAR2(128) NOT NULL,"CON#" NUMBER NOT NULL,"SPARE1" NUMBER,"SPARE2" NUMBER,"SPARE3" NUMBER,"SPARE4" VARCHAR2(1000),"SPARE5" VARCHAR2(1000),"SPARE6" DATE)';
    pl_objtxt := pl_objtxt || gen_storage(pl_obj_num, 'TABLE');
    insert into bootstrap$tmpstr values(pl_line_num, pl_obj_num, pl_objtxt);
    commit;


    /* Create the bootstrap sql text for I_CON1_IMG (replace i_con1) */
    pl_obj_num  := get_obj_num('I_CON1_IMG', 4);
    pl_line_num := get_line_num('I_CON1', 4);
    pl_objtxt :='CREATE UNIQUE INDEX I_CON1 ON CON$(OWNER#,NAME)';
    pl_objtxt := pl_objtxt || gen_storage(pl_obj_num, 'INDEX');
    insert into bootstrap$tmpstr values(pl_line_num, pl_obj_num, pl_objtxt);
    commit;


    /* Create the bootstrap sql text for I_CON2_IMG (replace i_con2) */
    pl_obj_num  := get_obj_num('I_CON2_IMG', 4);
    pl_line_num := get_line_num('I_CON2', 4);
    pl_objtxt := 'CREATE UNIQUE INDEX I_CON2 ON CON$(CON#)';
    pl_objtxt := pl_objtxt || gen_storage(pl_obj_num, 'INDEX');
    insert into bootstrap$tmpstr values(pl_line_num, pl_obj_num, pl_objtxt);
    commit;

    /* Create the bootstrap sql text for BOOTSTRAT$IMG (replace BOOTSTRAP$) */
    pl_obj_num  := get_obj_num('BOOTSTRAP$IMG', 1);
    pl_line_num := get_line_num('BOOTSTRAP$', 1);
    pl_objtxt := 'CREATE TABLE BOOTSTRAP$("LINE#" NUMBER NOT NULL,"OBJ#" NUMBER NOT NULL,"SQL_TEXT" VARCHAR2(4000) NOT NULL)';
    pl_objtxt := pl_objtxt || gen_storage(pl_obj_num, 'TABLE');
    insert into bootstrap$tmpstr values(pl_line_num, pl_obj_num, pl_objtxt);
    commit;


  end;
  /

 

 


3、旧表数据导入新表

insert into sys.con$img select * from sys.con$;

insert into bootstrap$img select * from bootstrap$;

commit;


4、更新统计信息

begin
    dbms_stats.delete_table_stats('SYS', 'CON$IMG');
    dbms_Stats.gather_table_stats('SYS', 'CON$IMG',  estimate_percent => 100,
                                   method_opt=>'FOR ALL COLUMNS SIZE SKEWONLY');
  end;
  /


5、新旧表 swap index(即更新line# obj#以及obj$表记录的obj#的对应关系)

原对应关系:

line#                    obj#                    sql_text(obj#,file#,block#)
28                        28                        con$(28,1,288)
51                        51                        i_con1(51,1,456)
52                        52                        i_con2(52,1,464)
59                        59                        bootstrap$(59,1,520)


--null                7395244                bootstrap$tmpstr(null)
null                    7354534                bootstrap$img(7354534,8,752)
null                    7354642                con$img(7354642,8,1280)
null                    7354643                i_con1_img(7354643,8,1288)
null                    7354644                i_con2_img(7354644,8,1296)


执行以下sql后结果:
line#                    obj#                    sql_text(obj#,file#,block#)
28                        7354642                con$(28,1,288)
51                        7354643                i_con1(51,1,456)
52                        7354644                i_con2(52,1,464)
59                        7354534                bootstrap$(59,1,520)


null                    59                bootstrap$img(7354534,8,752)
null                    28                con$img(7354642,8,1280)
null                    51                i_con1_img(7354643,8,1288)
null                    52                i_con2_img(7354644,8,1296)

bootstrap$tmpstr 对应关系:
line#                    obj#                    sql_text(obj#,file#,block#)
28                        7354642                con$(7354642,8,1280)
51                        7354643                i_con1(7354643,8,1288)
52                        7354644                i_con2(7354644,8,1296)
59                        7354534                bootstrap$(7354534,8,752)

 

declare
    type vc_nst_type is table of varchar2(30);
    type nb_nst_type is table of number;
    old_name_array vc_nst_type;                     /* old object name array */
    new_name_array vc_nst_type;                     /* new object name array */
    ns_array       nb_nst_type;                     /* namespace of the object */
  begin
    old_name_array := vc_nst_type('CON$','I_CON1', 'I_CON2',
                                  'BOOTSTRAP$');
    new_name_array := vc_nst_type('CON$IMG', 'I_CON1_IMG', 'I_CON2_IMG',
                                  'BOOTSTRAP$IMG');
    ns_array       := nb_nst_type(1,4,4,1);

    /* Swap the name in old_name_array with new_name_array in ONJ$ */
    for i in old_name_array.FIRST .. old_name_array.LAST
    loop
      update obj$ set name = 'ORA$IMG_TMP'
        where name = old_name_array(i) and owner# = 0 and namespace=ns_array(i);
      update obj$ set name = old_name_array(i)
        where name = new_name_array(i) and owner# = 0 and namespace=ns_array(i);
      update obj$ set name = new_name_array(i)
        where name = 'ORA$IMG_TMP'     and owner# = 0 and namespace=ns_array(i);
    end loop;

    /* Commit when we're done with the swap */
    commit;
  end;
  /

 

 

6、删除bootstrap$img 的旧数据(注意:这里的旧数据指的是老的con$等对象,由于上一步进行了swap,旧的con$已经变成了con$img,因此删除的是con$img)

当前bootstrap$img 对应关系:

line#                    obj#                    sql_text(obj#,file#,block#)
28                        28                    con$img(28,1,288)
51                        51                    i_con1_img(51,1,456)
52                        52                    i_con2_img(52,1,464)
59                        59                    bootstrap$img(59,1,520)

 

delete from bootstrap$img
   where obj# in
         (select obj#
            from obj$
           where name in ('CON$IMG', 'I_CON1_IMG', 'I_CON2_IMG', 'BOOTSTRAP$IMG'));

commit;

 

7、插入bootstrap$img 新的sql_text内容(核心启动原理,bootstrap$tmpstr中的内容一定是将来数据库的启动顺序路径)

insert into bootstrap$img select * from bootstrap$tmpstr;
commit;


插入后bootstrap$img对应关系
line#                    obj#                    sql_text(obj#,file#,block#)
28                        7354642                con$(7354642,8,1280)
51                        7354643                i_con1(7354643,8,1288)
52                        7354644                i_con2(7354644,8,1296)
59                        7354534                bootstrap$(7354534,8,752)

 

8、更新底层对象依赖关系

declare
    type vc_nst_type is table of varchar2(30);
    old_obj_num number;
    new_obj_num number;
    new_ts      timestamp;
    old_name    vc_nst_type;
    new_name    vc_nst_type;
  begin
    old_name := vc_nst_type('CON$', 'BOOTSTRAP$');
    new_name := vc_nst_type('CON$IMG', 'BOOTSTRAP$IMG');

    for i in old_name.FIRST .. old_name.LAST
    loop
      select obj# into old_obj_num from obj$
        where owner#=0 and name=old_name(i) and namespace=1;
      select obj#, stime into new_obj_num, new_ts
        from obj$ where owner#=0 and name=new_name(i) and namespace=1;

      -- Step 7
      update dependency$
        set p_obj#      = new_obj_num,
            p_timestamp = new_ts
        where p_obj# = old_obj_num;

      -- Step 8
      update objauth$ set obj# = new_obj_num where obj# = old_obj_num;

    end loop;

    commit;
  end;
  /

 

 

9、swap rdba(核心,即更换bootstrap$的地址指向)

 

--该方法在12c未生效,不推荐使用

startup upgrade
exec dbms_ddl_internal.swap_bootstrap('BOOTSTRAP$IMG');
delete from props$ where name = 'BOOTSTRAP_UPGRADE_ERROR';
delete from props$ where name = 'LOGMNR_BOOTSTRAP_UPGRADE_ERROR';

 

 

--dba和文件号、块号互相转换

CREATE OR REPLACE FUNCTION getbfno (p_dba IN VARCHAR2)
    RETURN VARCHAR2
 IS
    l_str   VARCHAR2 (255) DEFAULT NULL;
    l_fno   VARCHAR2 (15);
    l_bno   VARCHAR2 (15);
 BEGIN
    l_fno :=
       DBMS_UTILITY.data_block_address_file (TO_NUMBER(LTRIM (p_dba, '0x'), 'xxxxxxxx'));
    l_bno :=
       DBMS_UTILITY.data_block_address_block (TO_NUMBER (LTRIM (p_dba, '0x'), 'xxxxxxxx'));
    l_str :=
          'datafile# is:'
       || l_fno
       || CHR (10)
       || 'datablock is:'
       || l_bno
       || CHR (10)
       || 'dump command:alter system dump datafile '
       || l_fno
       || ' block '
       || l_bno
       || ';';
    RETURN l_str;
 END;
/

--根据dba查询文件号、块号

select getbfno('0x00400179') bfno from dual;

--根据文件号、块号查dba

select dbms_utility.make_data_block_address(8,752) from dual;

 

 


更新前:
1,520 -->  0x00400208    --> 4194824(十进制) --> 400208(十六进制)    --> 旧的bootstrap$启动地址

8,752 -->  0x020002F0    --> 33555184(十进制) --> 20002F0(十六进制)--> 新的bootstrap$启动地址


--bbed修改启动地址,该地址的记录位置默认在1号文件@96偏移量处

set filename '/u01/oradata/HECPROD/system.258.893786245'
set count 32
set offset 96
p kcvfhrdb
set mode edit
assign kcvfhrdb=0x020002F0            --bootstrap$    0x020002F0
sum apply
verify

 

上一篇:【玩具】获取B站视频的音频片段


下一篇:指定的架构无效。错误: CLR 类型到 EDM 类型的映射不明确