Bootstrap

ORACLE 11G ORA-8103 错误问题处理一例

ORACLE 11G ORA-8103 错误问题处理一例

1.问题现象:

今天一朋友说他执行一个SQL语句,会报 ORA-08103错误,但选择其他字段不会:

select edit_time from ZLDOC.BZ_DOC_LOG where edit_time>sysdate-1;

ERROR at line 1:
ORA-08103: object no longer exists


2.问题分析:

使用 
select creat_time from ZLDOC.BZ_DOC_LOG where creat_time>sysdate-1;
没有问题。

       
使用
select count(*) from ZLDOC.BZ_DOC_LOG,没有问题

导出数据

expdp \' / as sysdba\' directory=dbbak dumpfile=bz_doc_log.dmp logfile=tables.log tables=ZLDOC.BZ_DOC_Log 由于该表含有CLOB,XMLTYPE等类型,表数据只有20g,但对象有 280G,
所以,一直没有结果


使用 create table as select,会报ora-08103 错误。

3.联机文档解释:
  ORA-08103: object no longer exists

Cause: The object has been deleted by another user since the operation began, or a prior incomplete recovery restored the database to a point in time during the deletion of the object.

Action: Delete the object if this is the result of an incomplete recovery.

ORA-08103表示在进行持久操作时找不到某个对象,具体地说,就是表或视图不能因为已经丢失或被删除,但是还有指向它的对象的句柄。在开发数据库过程中,很可能会碰到这个错误,这个错误是由于表或视图被删除或不存在,但是SQL查询还是链接到该表或视图。

4.网上的解决办法:
  1.转到SYSDBA模式,连接到数据库,查看表的具体信息;
 2.查看表的对象是否存在,确定表是否存在;
 3.如果表不存在,要查看用户正在尝试查询哪些表,以及出现ORA-08103错误的表是哪个;
 4.查看相关联的语句,调查是否有第三方程序和进程正在尝试访问ORA-08103的表;
 5.查看系统中的脚本是否有问题,以及更改现有脚本来访问ORA-08103的表;
 6.重新创建被删除的表,并执行必要的记录操作,重新测试语句,以确保它正确地表示被访问的表; 
 7.正确地应用 Oracle 支持的可选特征,以防止Oracle 数据库出现ORA-08103错误;
 8.重新创建该表,重新运行SELECT语句,重新获取该表,以更正ORA-08103错误。

看起来不太靠谱,这个表含大对象有280G,不太好重建,而且我们重建也会报同样的错。

5.通过 mos:1527738.1所提供的脚本去保存好的记录,运行一段,就失败了,报:ORA-03113的错误

6.确定问题块

搜MOS,根据 Doc ID 1671518.1 跟踪SQL语句

alter session set max_dump_file_size=unlimited;
 alter session set db_file_multiblock_read_count=1;
 alter session set events 'immediate trace name trace_buffer_on level 1048576';
 alter session set events '10200 trace name context forever, level 1';
 alter session set events '10236 trace name context forever, level 1';
 alter session set events '8103 trace name errorstack level 3';
 alter session set tracefile_identifier='ORA8103';
 ----->>>> run the sql statement that causes the ORA-08103
 alter session set events 'immediate trace name trace_buffer_off';
 oradebug setmypid
 oradebug tracefile_name

发现了错误的块是  8/2922345:
。。。
        BH (0x20f664288) file#: 8 rdba: 0x022c9769 (8/2922345) class: 1 ba: 0x200006000
        set: 171 pool: 3 bsz: 8192 bsi: 0 sflg: 1 pwc: 3690,28
        dbwrid: 2 obj: 87376 objn: 87376 tsn: 9 afn: 8 hint: f
        hash: [0x109fca6ef8,0xf9f83efb8] lru: [0x104f678dc0,0x104f6724f0]
        ckptq: [NULL] fileq: [NULL] objq: [0xcfc639f8,0xfef758a98] objaq: [0x100f710fd0,0x122f713808]
        use: [NULL] wait: [NULL] fast-cr-pins: 1
        st: XCURRENT md: NULL fpin: 'ktspbwh2: ktspfmdb' tch: 161
        flags: block_written_once redo_since_read
        LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [1]
        buffer tsn: 9 rdba: 0x00000000 (0/0)
        scn: 0x0000.00000000 seq: 0x00 flg: 0x00 tail: 0x220a0601
        frmt: 0x00 chkval: 0x0000 type: 0x00=unknown
Hex dump of corrupt header 4 = CORRUPT

。。。

通过ROWID,保留 坏块:
create table bad_rows_SAMPLE  (row_id rowid, oracle_error_code number);
set serveroutput on

declare
  n number;
  error_code number;
  bad_rows number := 0;
  e_time date;
  ora1578 EXCEPTION;
  ora600 EXCEPTION;
  ora8103 EXCEPTION;
  PRAGMA EXCEPTION_INIT(ora1578, -1578);
  PRAGMA EXCEPTION_INIT(ora600, -600);
  PRAGMA EXCEPTION_INIT(ora8103, -8103);

begin
   for cursor_lob in (select rowid rid from ZLDOC.BZ_DOC_LOG ) loop
   begin
      select edit_time into e_time from ZLDOC.BZ_DOC_LOG where rowid=cursor_lob.rid ;
   exception
     when ora8103 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,8103);
     commit;

    when ora1578 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,1578);
     commit;
    when ora600 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,600);
     commit;
    when others then
     error_code:=SQLCODE;
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,error_code);
     commit;   
   end;
  end loop;
  dbms_output.put_line('Total Rows identified with errors in LOB column: '||bad_rows);
end;
/

SQL> select * from bad_rows_SAMPLE;

ROW_ID             ORACLE_ERROR_CODE
------------------ -----------------
AAAVVQAAIAALJdpAAA              8103
AAAVVQAAIAALJdpAAB              8103
AAAVVQAAIAALJdpAAC              8103
AAAVVQAAIAALJdpAAD              8103
AAAVVQAAIAALJdpAAE              8103
AAAVVQAAIAALJdpAAF              8103
AAAVVQAAIAALJdpAAG              8103
AAAVVQAAIAALJdpAAH              8103
AAAVVQAAIAALJdpAAI              8103
AAAVVQAAIAALJdpAAV              8103
AAAVVQAAIAALJdpAAJ              8103

ROW_ID             ORACLE_ERROR_CODE
------------------ -----------------
AAAVVQAAIAALJdpAAK              8103
AAAVVQAAIAALJdpAAL              8103
AAAVVQAAIAALJdpAAM              8103
AAAVVQAAIAALJdpAAN              8103
AAAVVQAAIAALJdpAAO              8103
AAAVVQAAIAALJdpAAP              8103
AAAVVQAAIAALJdpAAQ              8103
AAAVVQAAIAALJdpAAR              8103
AAAVVQAAIAALJdpAAS              8103
AAAVVQAAIAALJdpAAT              8103
AAAVVQAAIAALJdpAAa              8103

ROW_ID             ORACLE_ERROR_CODE
------------------ -----------------
AAAVVQAAIAALJdpAAU              8103
AAAVVQAAIAALJdpAAW              8103
AAAVVQAAIAALJdpAAX              8103
AAAVVQAAIAALJdpAAY              8103
AAAVVQAAIAALJdpAAZ              8103
AAAVVQAAIAALJdpAAb              8103

已选择28行。

SQL> r
  1  select row_id,dbms_rowid.rowid_object(row_id) "#object",
  2               dbms_rowid.rowid_relative_fno(row_id) "#file",
  3               dbms_rowid.rowid_block_number(row_id) "#block",
  4               dbms_rowid.rowid_row_number(row_id) "#row"
  5     from bad_rows_SAMPLE
  6     order by 1
  7*

ROW_ID                #object      #file     #block       #row
------------------ ---------- ---------- ---------- ----------
AAAVVQAAIAALJdpAAA      87376          8    2922345          0
AAAVVQAAIAALJdpAAB      87376          8    2922345          1
AAAVVQAAIAALJdpAAC      87376          8    2922345          2
AAAVVQAAIAALJdpAAD      87376          8    2922345          3
AAAVVQAAIAALJdpAAE      87376          8    2922345          4
AAAVVQAAIAALJdpAAF      87376          8    2922345          5
AAAVVQAAIAALJdpAAG      87376          8    2922345          6
AAAVVQAAIAALJdpAAH      87376          8    2922345          7
AAAVVQAAIAALJdpAAI      87376          8    2922345          8
AAAVVQAAIAALJdpAAJ      87376          8    2922345          9
AAAVVQAAIAALJdpAAK      87376          8    2922345         10

ROW_ID                #object      #file     #block       #row
------------------ ---------- ---------- ---------- ----------
AAAVVQAAIAALJdpAAL      87376          8    2922345         11
AAAVVQAAIAALJdpAAM      87376          8    2922345         12
AAAVVQAAIAALJdpAAN      87376          8    2922345         13
AAAVVQAAIAALJdpAAO      87376          8    2922345         14
AAAVVQAAIAALJdpAAP      87376          8    2922345         15
AAAVVQAAIAALJdpAAQ      87376          8    2922345         16
AAAVVQAAIAALJdpAAR      87376          8    2922345         17
AAAVVQAAIAALJdpAAS      87376          8    2922345         18
AAAVVQAAIAALJdpAAT      87376          8    2922345         19
AAAVVQAAIAALJdpAAU      87376          8    2922345         20
AAAVVQAAIAALJdpAAV      87376          8    2922345         21

ROW_ID                #object      #file     #block       #row
------------------ ---------- ---------- ---------- ----------
AAAVVQAAIAALJdpAAW      87376          8    2922345         22
AAAVVQAAIAALJdpAAX      87376          8    2922345         23
AAAVVQAAIAALJdpAAY      87376          8    2922345         24
AAAVVQAAIAALJdpAAZ      87376          8    2922345         25
AAAVVQAAIAALJdpAAa      87376          8    2922345         26
AAAVVQAAIAALJdpAAb      87376          8    2922345         27

已选择28行。

通过这个块分析,发现有问题的块,就是块 2922345 和上面 8103跟踪的相对应。

7.各种想法尝试

看来这个块有问题,单独去执行

select id from ZLDOC.BZ_DOC_LOG where rowid='AAAVVQAAIAALJdpAAb';
都会报 ora-8103 

create index idx_doc_log on ZLDOC.BZ_DOC_LOG(edit_time);同样报错

不想要这28条记录,
delete from ZLDOC.BZ_DOC_LOG where rowid in (select row_id from bad_rows_SAMPLE);
也会报  ora-8103 

本来想放弃这个28行,保存好的记录:

declare
  n number;
  error_code number;
  bad_rows number := 0;
  e_time date;
  ora1578 EXCEPTION;
  ora600 EXCEPTION;
  ora8103 EXCEPTION;
  PRAGMA EXCEPTION_INIT(ora1578, -1578);
  PRAGMA EXCEPTION_INIT(ora600, -600);
  PRAGMA EXCEPTION_INIT(ora8103, -8103);

begin
   for cursor_lob in (select rowid rid from ZLDOC.BZ_DOC_LOG ) loop
   begin
      insert into ZLDOC.BZ_DOC_LOG_Norm  select /*+ ROWID(A) */ * from ZLDOC.BZ_DOC_LOG A where rowid=cursor_lob.rid ;
   exception
     when ora8103 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,8103);
     commit;

    when ora1578 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,1578);
     commit;
    when ora600 then
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,600);
     commit;
    when others then
     error_code:=SQLCODE;
     bad_rows := bad_rows + 1;
     insert into bad_rows_SAMPLE values(cursor_lob.rid,error_code);
     commit;   
   end;
  end loop;
  dbms_output.put_line('Total Rows identified with errors in LOB column: '||bad_rows);
end;
/
这个很快就会报0RA-03113的错误,没有看到好的解释,有点奇怪 ,看来想保存好的数据,都存在问题。

看来这样搞,还是有问题,
继续网上搜,发现一个方法,可以把 8103变成真正的坏块,然后再跳过这些坏块。

在bbed设置坏块看看.
BBED> set dba 8,2922345
        DBA             0x022c9769 (25166083 8,2922345)

BBED> corrupt
Block marked media corrupt.

BBED> sum apply ;
Check value for File 8, Block 2922345:
current = 0xa683, required = 0xa683

SQL>ALTER SESSION SET EVENTS '10231 TRACE NAME CONTEXT FOREVER, LEVEL 10';

8.最终解决

但想到按这样处理,就要丢数据了.

但真的没有办法了吗 
还是不太甘心,中午了,想到还是要赶紧把这个问题处理了,再去吃饭,再网上搜了一些,看到有人,直接把数据缓冲去刷一下,就可以了

想到已经是13:00,现在用的人少,赶紧试一下,
alter system flush buffer_cache;

再去看原来要报错的地方:

select edit_time from ZLDOC.BZ_DOC_LOG where edit_time>sysdate-1;

尽然真的不报错了,
赶紧看看直接有报错的块,

select id,edit_time from ZLDOC.BZ_DOC_LOG where rowid in (select row_id from bad_rows_SAMPLE);

确实不报错了

再让朋友检查应用,说修改时间不报错了,但创建时间要报错了,

听到这里,吓我一跳,难倒还有问题,让对方把错误图片贴一个出来,结果是报 " ORA-00920 无效的关系运算符", 明显是SQL语句的问题,让对方看一下,结果是对方SQL语句搞掉了一段。重新运行,问题解决。


到这里,问题已经解决。

9.反思
但反过来想,怎么最终这么简单的问题,最后,花了这么多功夫呢,可能还是被网络误导了,看到网络上都把这个问题夸大了,导致一心也想到问题不会很简单,需要使用高大上的工具才能解决,反而把自己带偏了。

后来,回过头来再次搜MOS,结果上面本来就有一篇文章:

Query from subscriber errors with Ora-8103 (Doc ID 1365868.1)

这个文章说了原因,以及给了一个链接:

OERR: ORA-8103 "object no longer exists" / Troubleshooting, Diagnostic and Solution (Doc ID 8103.1)

这篇文章中,说了各种可能,里面就有一个说可能只在BUFFER CACHE 存在损坏,直接刷一下缓冲区即可

看来这次问题处理,确实是事情多了,简单的问题,复杂化了。

今后解决问题,首先还是要相信官方的知识库.

最后感谢:DBA 札记1群的群主,及小伙伴们,谢谢你们提供思路,让我快速找到问题的解决之道。


参考文档:

      ORA-08103: Object No Longer Exists (Doc ID 1465978.1)

      SRDC - Required Diagnostic Data Collection for ORA-08103 (Doc ID 1671518.1)

      OERR: ORA-8103 "Object No Longer Exists" Primary Note / Troubleshooting, Diagnostic and Solution (Doc ID 8103.1)

;