ORA-08103对象不再存在问题分析

在数据库进行CTAS 操作查询表 ooo .A_D_BRXXX_XXX_XXX 时报出了ORA-08103 错误,

SQL> create table A_D_BRXXX_XXX_XXX_1125 as select * from OOO .A_D_BRXXX_XXX_XXX;

ORA-08103: object no longer exists

 

关于ORA-08103 的解释:

Error: ORA 8103 
Text: object no longer exists 
-------------------------------------------------------------------------------
Cause: The object has been deleted by another user since the operation began.
Action: Remove references to the object.

 

Description

ORA-8103 is reporting that a SQL statement found a block that no longer belongs to the object referenced in the statement.  

Cause

ORA-8103 is caused by an invalid block type. The block header has an invalid block type or the block type inside the block is not expected; e.g. a data block (Type=6) was expected but the actual block information is not a data block (Type!=6).
ORA-8103 is also caused by an unexpected data_object_id where it is changing for the involved objects while the affected SQL statement is executed.

从以上的关于的ORA-08103 可以知道 ORA-08103 出现的场景是当一个语句执行时发现某个块不属于某个对象。

导致的原因有二:

1.  导致ORA-08103 的原因是存在不可用的块类型。即所描述的块类型和实际记录块类型不一致。

2.  另一个原因是当某个语句执行时其data_object_id 被改变导致,这种是由于 DDL 引起。

 

而可以确认的是在执行CTAS 操作时,数据库中并不存在其他的会话在进行 DDL 操作。因此,可以怀疑导致的问题的原因是第一种。

 

10046 跟踪:

以下对CTAS 的过程进行 10046 追踪,以确认错误在哪一步出现:

以下部分 10046 日志截取:

CLOSE #4574899200:c=3,e=4,dep=1,type=0,tim=47159071133647

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

PARSING IN CURSOR #4574893000 len=83 dep=0 uid=0 oct=1 lid=0 tim=47159071134928 hv=506090881 ad='7000000a7827840' sqlid='2918v7hg2npc1'

  create table  OOO .A_D_BRXXX_XXX_XXX_1126 as select * from  OOO .A_D_BRXXX_XXX_XXX    <<<< 执行的 CTAS 语句

END OF STMT

PARSE #4574893000:c=2530,e=4075,p=0,cr=10,cu=0,mis=1,r=0,dep=0,og=1,plh=2393565612,tim=47159071134928

BINDS #4574047816:

。。。。。 <<<< 省略

。。。。。

DDE Action 'DB_STRUCTURE_INTEGRITY_CHECK' was flood controlled

----- END DDE Action: 'DB_STRUCTURE_INTEGRITY_CHECK' (FLOOD CONTROLLED, 1 csec) -----

Executing ASYNC actions

----- END DDE Actions Dump (total 0 csec) -----

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

PARSING IN CURSOR #4574654208 len=67 dep=1 uid=0 oct=3 lid=0 tim=47159074207269 hv=785625969 ad='7000000a789fd58' sqlid='at1ygf4rd7cvj'

select file#, block#, blocks from   seg$ where type# = 3 and ts# = :1     <<<< 通过 seg$ 查询 type#=3 的文件和块号, type#=3  TEMPORARY  ,这里指的是临时段

END OF STMT

PARSE #4574654208:c=53,e=88,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=1764637915,tim=47159074207269

BINDS #4574654208:

 Bind#0

  oacdty=02 mxl=22(22) mxlc=00 mal=00 scl=00 pre=00

  oacflg=08 fl2=0001 frm=00 csi=00 siz=24 off=0

  kxsbbbfp=110af7520  bln=22  avl=02  flg=05

   value=6    <<<< 绑定变量 ts# 的值,这里是 6,6 号表空间正是 OOO 用户所在的表空间

EXEC #4574654208:c=63,e=102,p=0,cr=0,cu=0,mis=0,r=0,dep=1,og=4,plh=1764637915,tim=47159074207506

FETCH #4574654208:c=1793,e=2805,p=0,cr=312,cu=0,mis=0,r=1,dep=1,og=4,plh=1764637915,tim=47159074212837

FETCH #4574654208:c=25453,e=53743,p=0,cr=4792,cu=0,mis=0,r=1,dep=1,og=4,plh=1764637915,tim=47159074266671

WAIT #4574893000: nam='db file sequential read' ela= 28 file#=678 block#=116881 blocks=1 obj#=-1 tim=47159074266832   <<<< 最后一个读取的块是 678 号文件的 116881 号块

EXEC #4574893000:c=1236647,e=3132010,p=8505,cr=81566,cu=13568,mis=0,r=0,dep=0,og=1,plh=2393565612,tim=47159074266999   <<<< 执行

ERROR  #4574893000: err=8103  tim=47159074267016    <<< 抛出了 8103 的错误

STAT #4574893000 id=1 cnt=0 pid=0 pos=1 obj=0 op='LOAD AS SELECT  (cr=0 pr=0 pw=0 time=37 us)'

STAT #4574893000 id=2 cnt=376158 pid=1 pos=1 obj=0 op='PARTITION RANGE ALL PARTITION: 1 1945 (cr=9786 pr=8504 pw=0 time=387949 us cost=22628 size=453306100 card=2887300)'

STAT #4574893000 id=3 cnt=376158 pid=2 pos=1 obj=4312763 op='TABLE ACCESS FULL A_D_BRXXX_XXX_XXX PARTITION: 1 1945 (cr=9786 pr=8504 pw=0 time=274483 us cost=22628 size=453306100 card=2887300)'

STAT #4574654208 id=1 cnt=2 pid=0 pos=1 obj=14 op='TABLE ACCESS FULL SEG$ (cr=5104 pr=0 pw=0 time=2790 us cost=989 size=20 card=1)'

CLOSE # 4574654208:c=26,e=42,dep=1,type=0,tim=47159074267249   <<<< 报错之后结束执行

WAIT #4574893000: nam='log file sync' ela= 60983 buffer#=4081 sync scn=2662421508 p3=0 obj#=4314004 tim=47159074331972

WAIT #4574893000: nam='SQL*Net break/reset to client' ela= 11 driver id=1650815232 break?=1 p3=0 obj#=4314004 tim=47159074336018

WAIT #4574893000: nam='SQL*Net break/reset to client' ela= 10448 driver id=1650815232 break?=0 p3=0 obj#=4314004 tim=47159074346509

WAIT #4574893000: nam='SQL*Net message to client' ela= 4 driver id=1650815232 #bytes=1 p3=0 obj#=4314004 tim=47159074346570

 

从以上的10046 追踪日志基本可以查看出报出 ora-08103 的过程,在此之前需先了解 CTAS 的过程。

CTAS 的过程解析:

ORACLE CTAS 的时候,创建的表的 BLOCK 首先被标志为 TEMP 等表全部创建完了再改为 其他类型,例如table 这样当CTAS 出现问题的时候,不需要回退,只需要以后回收临时段就可以了。

而这个过程中,所有对象的记录便在基表seg$ 中,其中 type#=3 是临时块, type#=5 table 类型。在个正常的 CTAS 过程是在新建表时将新建表所要存放的块先以类型是 3 插入到 seg$ 中(如果 seg$ 中已存在 type#=3 的便可继续复用),之后完成了再 update 类型成 5 ,并且当一个 CTAS 语句正常结束时是不会有 type#=3 的块存在的。如果是异常的 CTAS ,便通过 smon 来进行清理回收临时段。

 

而在以上报错的过程中,是先通过以下语句查询seg$ ts#=6,type#=3 的块:

select file#, block#, blocks from   seg$ where type# = 3 and ts# = :1   ,而之后找到的块是678 号文件的 116881 号块,这说明这个块已经被记录来用作临时块,但在读取这个块的却报出了 ORA-08103 错误。由此,可以初步断定,本次 ORA-08103 错误与 678 号文件的 116881 号块有关。

     实际上, 在当时通过文件号及块号查询出了该块上的对象是一个已存在的普通表 ,即是说seg$ 中记录 678 号文件的 116881 号块的类型是临时块,与实际情况不一致,因此导致了 ORA-08103 错误。这正符合以上的原因一。以下通过实验可以重现该过程。

 

1.2  ORA-08103 错误模拟重现实验

1. 创建一个测试表空间。

create tablespace cwdtest datafile '+DATA' size 1G autoextend on;

 

 

TABLESPACE_NAME                    SUM_MB    FREE_MB USE_PRECENT

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

CWDTEST                              1024       1023          .1

 

2. 查询当前数据库 seg$ type#=3 的块,正常情况下没有,在 CTAS 的过程中才会出现。

       

3. 通过 10046 捕捉正常 CTAS 过程中的 insert into seg$ 语句,并将某个空块手工以 type#=3 插入到 seg$ 中。(这里主要模拟的是某些块被定义为 seg$ 临时块后没有及时更改);

SQL> insert into seg$ (file#,block#,type#,ts#,blocks,extents,minexts,maxexts,extsize,extpct,user#,iniexts,lists,groups,cachehint,hwmincr, spare1, scanhint, bitmapranges) values (86,2291642,3,53,8,1,1,2147483645,128,0,46,8,0,0,0,118552,DECODE(4194561,0,NULL,4194561),0,2147483645);        

 

1 row created.

 

SQL> commit;

 

Commit complete.

 

SQL> select file#, block#, blocks from SYS.seg$ where type# = 3;

 

     FILE#     BLOCK#     BLOCKS

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

          86    2291642          8


4. 实际上该块上目前还没有数据:


5. 于是手工往这个表空上创建对象,并往表上扩展分区:

SQL> create table s (n number,c varchar2(4000)) nologging tablespace cwdtest;

 

Table created.

SQL> BEGIN

  2  FOR I IN 1 .. 100000000

LOOP

EXECUTE IMMEDIATE 'alter table s allocate extent(size 1048576 datafile ''+DATA/cspadg/datafile/cwdtest.409.961946541'')';

END LOOP;

END;  3    4    5    6  

  7  /


6. 实际上在扩展分区的过程中已经报出了 ORA-08103 ,此时这个块已经被占用。

 

 

7. 此时进行 CTAS 时也同样报出了 ORA-08103 错误:

 

8 .实际上,此时将 seg$ 记录的不一致的块给删除了,该问题就解决了。

 

 

通过以上实验,可以确定,在CTAS 的过程中 oracle 根据 seg$ 表中 type#=3 的块来左右临时块以创建新的对象,但当其实际中该块被使用了的时候,此时便会报出了 ORA-08103 的错误。

1.3  总结

通过从以上分析,数据库出现的ORA-08103 的问题是因为数据库中 seg$ 记录了临时块,其与实际块的使用情况不一致,导致在该 OOO 用户表空间进行 CTAS 操作时需要用到该块做为临时块是便报出了 ORA-08103 错误。 S eg$ 记录信息出现异常可能是由于多次异常 CTAS 造成 seg$ 表中关于临时块的记录未被及时更新而存留在 seg$ 表中导致。

建议处理方式如下:

1.  数据文件使用非自动扩展方式并预先分配空间,已使在寻找临时块时发现不可用可继续往下寻找而不报错。

2.  更新seg$ 存留的异常记录,删除或更新类型与实际相同。

 



请使用浏览器的分享功能分享到微信等