某客户的一个表在进行分析和建索引一段时间时,均报ORA-8103错误。

让我们先看看ORA-8103错误是个什么样的错误?

[oracle@xty ~]$ oerr ora 8103
08103, 00000, "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.

从上面的信息来看,引起这个错误的并不是由于什么对象被删除或者不完全恢复引起的。看来剩下的可能就是BUG或者是坏块了。

select /*+ parallel(a 6) no_index(a) */
count(lrrq) from hz2004.HJXX_RYZPXXB a

由于表很大,100g左右,因此等了好长一段时间,就报了ORA-8103错误。由于不同的SQL语句(建索引、分析表和查询表数据)都报了这个错误,基本可以确定是坏块引起的问题。

由于表中有long raw类型,因此不能通过从主键取得ROWID再根据ROWID读到值以后插入新表,由于查询表有问题,导出也不会成功。因此决定想办法来修复这个问题:

首先要确定是哪个块出现问题:

SQL> alter session set max_dump_file_size=unlimited;
SQL> alter session set db_file_multiblock_read_count=1;
SQL> alter session set events ‘immediate trace name trace_buffer_on level 1048576′;
SQL> alter session set events ‘10200 trace name context forever, level 1′;
SQL> select /*+ no_index(a */ count(*) from hz2004.hjxx_ryzpxxb a;

(注:经测试,在10g中,需要去掉trace_buffer_on那一个语句才会有trace,否则没有trace文件)
再次报错时,检查trace文件,发现如下的信息:

Consistent read started for block 11 : 09c63a9e
env: (scn: 0×0886.245ea878 xid: 0×0000.000.00000000
uba: 0×00000000.0000.00 statement num=0 parent xid:
xid: 0×0000.000.00000000
scn: 0×0000.00000000 0sch: scn: 0×0000.00000000)

从trace文件中可以发现在读文件号39块号408222时报错。

执行:

select * from hz2004.hjxx_ryzpxxb
where rowid=dbms_rowid.rowid_create(1,7415,39,408222,0);

报ORA-08103错误,可以确认是39号文件408222块坏。

然而用dbv命令检查39号文件,没有发现坏块。

通过dd取出39号文件408222块,发现该块居然是一个未格式化的块,但是该块在表的High water mark以下。单从该块来说是一个好的块,所以dbv检查并不会报坏块。

既然如此,我就故意做成一个坏块,然后让oracle跳过这个坏块。关闭库之后,用dd把坏块复制出来保存在一个文件,然后修改该块,使之成为一个坏块(很多的方法,这里我的方法就是修改其checksum值)。然后用dd复制回去。重启库之后,用 dbms_repair.skip_corrupt_blocks过程设置表在读取数据时,跳过坏块。

再次读取该表的所有数据,不再报错。

客户进行建索引和分析时也不再报错,顺利进行。

当然后续的工作,还是需要将数据导出来再导入,这样更稳妥。

Trackback

14 comments untill now

  1. chenxiuguo @ 2008-09-11 07:05

    我是一oracle初学者,前来参观,请多指教

    [回复]

  2. 请教:
    文件号39块号408222 怎么计算处理的。

    [回复]

  3. 在那个trace文件里面有这么一句:
    Consistent read started for block 11 : 09c63a9e
    09c63a9e是正在读的块的RDBA,也就是rfile#=39,block#=40822

    trace文件中读到这个块时,就中止了,说明这个块就是引起错误的块。

    [回复]

  4. 明白了,谢谢!

    [回复]

  5. 09c63a9e 换成二进制
    0000 1001 1100 0110 0011 1010 1001 1110
    前10位数rfile# 0000 1001 11 换成十进制为 39
    后22位数block# 00 0110 0011 1010 1001 1110 换成十进制为 408222

    [回复]

  6. 熊哥,我细化了你用dd改checksum值的过程,详细请见:
    http://dbsnake.com/2009/02/ddchecksum.html

    [回复]

  7. ALTER SYSTEM SET EVENTS=’10231 trace name context forever,level 10′ 的效果应该和dbms_repair.skip_corrupt_blocks一样,可以跳过坏块。

    [回复]

  8. to qsxing:
    是,那个事件也是要跳过坏块,但是你这样设置一个系统事件,如果一个其他的表出现坏块,不出现报错信息,就会埋下隐患啊。

    [回复]

  9. 有可能会出现这样的情况,看来有些事件不能随便设置。我考虑问题还是不太全面 O(∩_∩)O

    [回复]

  10. 熊哥,对于改checksum值,用BBED改也是可以的,详细请见:
    http://dbsnake.com/2009/02/bbedchecksum.html

    [回复]

  11. to allantrey
    谢谢。
    不过当时用ultraedit故意改成的一个坏块。

    [回复]

  12. luolongjiu @ 2009-10-24 00:28

    laoxiong
    不错哦!
    我也在成都(学生)!
    成都也有位大师级的人物!

    [回复]

  13. […] ORA-01410错误通常见于通过索引访问表,而索引或表由逻辑上的损坏。而这里显示没有通过索引访问表?那问题出在哪里呢?在这种情况下,这个错误与ORA-08103极其类似,参照《记一次ORA-8103错误的处理》: […]

  14. 跪求大哥qq指导,小弟现在数据库恢复后也遇到这个问题,qq30303073768,大哥能加一下吗 万分感谢

    [回复]

Add your comment now