IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    expdp 报错ORA-7445 的一个问题展开

    roger发表于 2016-04-08 04:33:31
    love 0

    本站文章除注明转载外,均为本站原创: 转载自love wife & love life —Roger 的Oracle技术博客

    本文链接地址: expdp 报错ORA-7445 的一个问题展开

    某客户说一套数据库由于非正常关机重启之后,进行数据导出发现报错,expdp无法正常工作,报错之后直接退出:

    处理对象类型 SCHEMA_EXPORT/JOB
    . . 导出了 "STATS"."T_REPORT_MONTH_TEMPS"              988.2 MB 1292221 行
    ORA-39014: 一个或多个 worker 进程已过早地退出。
    ORA-39029: worker 进程 1 (进程名为 "DW01") 过早地终止
    ORA-31672: Worker 进程 DW01 意外停止。
    
    作业 "SYS"."SYS_EXPORT_SCHEMA_04" 因致命错误于 23:58:10 停止

    而检查此时的alert log可以发现有如下类似的错误:

    Errors in file /u01/app/oracle/admin/orcl/bdump/orcl_dw01_28608.trc:
    ORA-07445: 出现异常错误: 核心转储 [klufprd()+321] [SIGSEGV] [Address not mapped to object] [0x000000000] [] []
    

    从上面的信息我们可以得到如下几个结论:

    1、expdp的写进程报错,因为日志产生是dw进程。

    2、dw进程报错的原因是遭遇了ora-07445 [klufprd()+321]错误。

    3、对于[klufprd()+321] 这个函数,非常少见。但是从前面2点我们可以知道这肯定与buffer cache有关系。
    所以要临时解决这个问题也很简单。通过alter system flush buffer_cache 刷新缓存之后,再次进行expdp操作.
    后续客户尝试了之后,发现expdp 操作虽然仍然会报错,但是expdp 不会异常终止,会继续完成后面其他对象的导出。

    进一步分析报错的信息可以看到,有如下这样的提示:

    *** SESSION ID:(2760.1968) 2016-04-08 00:14:14.347
                row 01808438.0 continuation at
                file# 6 block# 33784 slot 14 not found
    **************************************************
    KDSTABN_GET: 0 ..... ntab: 1
    curSlot: 14 ..... nrows: 14
    **************************************************
    *** 2016-04-08 00:14:14.348
    ksedmp: internal or fatal error
    ORA-00600: ÄÚ²¿´íÎó´úÂë, ²ÎÊý: [kdsgrp1], [], [], [], [], [], [], []
    Current SQL statement for this session:
    SELECT /*+NESTED_TABLE_GET_REFS+*/ "STATS"."T_REPORT_MONTH".* FROM "STATS"."T_REPORT_MONTH"
    ----- Call Stack Trace -----

    很明显,这里提到这个这个表,恰好就是expdp报错所遇到的表,只不过我们刷新buffer cache之后,expdp可以跳过这个表继续完成其他对象的导出。
    从上述的信息来看,这里存在错误。客户也意识到,通过dbv 对数据文件进行检查,但是发现文件并没有损坏。
    这里我们要注意,dbv 同时是检查物理坏块,对于逻辑坏块通常无能为力,当然块内的逻辑错误,这类型的块dbv是可以检查出来的。
    但是从这里的信息来看,Oracle发现所需要的这行记录row 01808438.0 应该在file 6 block 33784 中找到,但是却并没有发现。
    注意,这里的file 6 block 33784 本身是完好的。
    那么这里的row 01808438.0 表示什么含义呢?
    其实这是表示的nrid;这可以理解为一直指针;其中前面一部分是表现rdba地址,后面表现行编号。
    如果要进一步分析为什么会这个错误,我们怎么办呢? 很简单,分别将block 33784以及rdba 01808438(16进制) 进行dump。 如下是转换的脚本:

    SQL>  SELECT dbms_utility.data_block_address_block(25199672) "BLOCK",
      2         dbms_utility.data_block_address_file(25199672) "FILE"
      3      FROM dual;
    
        BLOCK       FILE
    ---------- ----------
         33848          6

    日志报错中提到的是row 01808438.0 ,那么我们首先来分析file 6 block 33848的dump:

    Block header dump:  0x01808438
     Object id on Block? Y
     seg/obj: 0xc03d01  csc: 0xb37.78b5ae28  itc: 3  flg: E  typ: 1 - DATA
         brn: 0  bdba: 0x1807d8a ver: 0x01 opc: 0
         inc: 0  exflg: 0
    
     Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
    0x01   0x000a.02d.000cdc5c  0x00809c91.6507.21  --U-    2  fsc 0x0001.78b6a4b1
    0x02   0x000a.014.000cdd00  0x00806957.650d.15  --U-    2  fsc 0x0000.78b6ec5d
    0x03   0x000a.025.000cdd5d  0x00801e50.650f.0a  --U-    2  fsc 0x0000.78b71584
    
    data_block_dump,data header at 0x1fb2f87c
    ===============
    tsiz: 0x1f80
    hsiz: 0x34
    pbl: 0x1fb2f87c
    bdba: 0x01808438
         76543210
    flag=--------
    ntab=1
    nrow=17
    frre=-1
    fsbo=0x34
    fseo=0xd2
    avsp=0x33b
    tosp=0x33c
    0xe:pti[0]	nrow=17	offs=0
    0x12:pri[0]	offs=0x1e34
    ......
    0x30:pri[15]	offs=0x6e2
    0x32:pri[16]	offs=0x583
    block_row_dump:
    tab 0, row 0, @0x1e34
    tl: 332 fb: --H-F--- lb: 0x0  cc: 79
    nrid:  0x018083f8.e
    col  0: [ 5]  c4 04 5a 27 1b
    col  1: [ 7]  47 59 30 32 30 30 31
    col  2: [ 4]  c3 15 11 04
    col  3: [12]  31 38 37 33 34 34 32 30 30 30 30 36
    col  4: [12]  31 34 30 34 34 34 32 30 30 30 30 31
    col  5: [30]
    ......

    上述类似表示的是rdba 地址01808438的第0行,也就是我们大家所理解的第一行。我们可以发现这行记录中,行头存在一个nrid地址。
    说到nrid地址,这通常是针对行链接,行迁移才会遇到的一种情况。那么这里为什么会出现呢?
    行迁移几种,最常见的一种其实是block内的。一个block中单条记录的最大列数是255列,当一行记录的列超过255时,其他的列数据库会被oracle 分成另外一个row piece存在同一个block中(当然也有可能存到其他block)。
    也就是说超过255列的行数据,会被分成多个row piece;而当我们读取这个行数据时,怎么知道是一个完整的整体呢?
    答案就是nrid,oracle 通过nrid来将这多个row piece 串在一起,组成一个完整的行数据。

    想到这一点,那么我们再回头去看下前面的错误。row 01808438.0 表示这个block的第0行,而该block的第0行所存在的nrid地址是:0x018083f8.e
    那么我们进一步到block 0x018083f8中去寻找第e行记录,发现结果是这样的:

     Object id on Block? Y
     seg/obj: 0xc03d01  csc: 0xb37.78bb5e9f  itc: 3  flg: E  typ: 1 - DATA
         brn: 0  bdba: 0x1807d8a ver: 0x01 opc: 0
         inc: 0  exflg: 0
    
     Itl           Xid                  Uba         Flag  Lck        Scn/Fsc
    0x01   0x000a.013.000cdc01  0x01c02834.6573.33  --U-    2  fsc 0x0000.78cbf31d
    0x02   0x000a.001.000cda7a  0x0080150a.64d3.21  C---    0  scn 0x0b37.78b584df
    0x03   0x000a.01e.000cdade  0x00801510.64d3.13  C-U-    0  scn 0x0b37.78b99f21
    
    data_block_dump,data header at 0x2b4fc709007c
    ===============
    tsiz: 0x1f80
    hsiz: 0x2e
    pbl: 0x2b4fc709007c
    bdba: 0x018083f80x018083f8
         76543210
    flag=--------
    ntab=1
    nrow=14
    frre=-1
    fsbo=0x2e
    fseo=0x568
    avsp=0x53a
    tosp=0x53a
    0xe:pti[0]	nrow=14	offs=0
    0x12:pri[0]	offs=0x1d78
    0x14:pri[1]	offs=0x1c37
    ......
    0x2a:pri[12]	offs=0x6c2
    0x2c:pri[13]	offs=0x568
    block_row_dump:
    tab 0, row 0, @0x1d78
    tl: 520 fb: -----L-- lb: 0x0  cc: 255
    ......
    tab 0, row 13, @0x568
    tl: 346 fb: --H-F--- lb: 0x1  cc: 79
    nrid:  0x018083f8.c
    col  0: [ 5]  c4 04 5a 3a 0a
    col  1: [ 7]  47 59 30 32 30 30 31
    col  2: [ 4]  c3 15 11 04
    ......
    col 76: [ 1]  80
    col 77: [ 1]  80
    col 78: [ 1]  80
    end_of_block_dump
    End dump data blocks tsn: 6 file#: 6 minblk 33784 maxblk 33784

    我们可以看到这里对应的记录根本就没有。因为该block最后一条记录是row 13,也就是第14行,也是一个row piece,而且存在一个nrid。
    该nrid是0x018083f8.c,这表示该block 33784第12行记录。跟row 13是组合成一条完整行记录的。
    换句话说,我们前面报错的那条记录,应该有2个row piece,其中一个row piece 是存在的,其中一个row piece 本应该存在在33784 block中。
    但是由于找不到该row piece,因此oracle报了上述的错误。
    实际上该错误遇到之后,我们通常以为是index的问题,通过drop 重建可以解决,然而这里的问题比较特殊,据说是表的数据有问题。
    所以这就是为什么客户重建index会报错的原因:

    SQL> CREATE INDEX "STATS"."MONTHINDEX_STATUS2" ON "STATS"."T_REPORT_MONTH" ("TARGET_298", "UNIT_LEVEL", "TARGET_VAL", "MONTH_FLG")
      2    TABLESPACE "STATDATA" ;
    CREATE INDEX "STATS"."MONTHINDEX_STATUS2" ON "STATS"."T_REPORT_MONTH" ("TARGET_298", "UNIT_LEVEL", "TARGET_VAL", "MONTH_FLG")
                                                         *
    第 1 行出现错误:
    ORA-00600: 内部错误代码, 参数: [kdsgrp1], [], [], [], [], [], [], []

    最后,我们清楚了所有原因,那么要解决该问题很简单。通过rowid的方式跳过这行有问题的记录,将其他数据取出,重建表即可。

    备注:关于块内的行迁移问题,可以参考之前的文章  http://www.killdb.com/2013/06/19/intra-blcok-chain.html

    No related posts.



沪ICP备19023445号-2号
友情链接