ORA-08103物件不再存在問題分析

darren__chan發表於2019-11-04

在資料庫進行CTAS 操作查詢表 ooo .A_D_BRXXX_XXX_XXX 時報出了ORA-08103 錯誤,

SQL> create table A_D_BRXXX_XXX_XXX_1125 as select * from .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$ 存留的異常記錄,刪除或更新型別與實際相同。

 



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

相關文章