zoukankan      html  css  js  c++  java
  • IMP-00009:异常结束导出文件解决方案

    墨墨导读:本文来自读者“小豹子加油(网名)”的投稿,主要讲述使用imp导入文件出现IMP-00009问题的处理过程。


    云和恩墨大讲堂线上分享:《weblogic 优化》

    时间:2019年7月30日(星期二)20:30-21:30

    立即报名:https://cs.enmotech.com/event/57



    一、概述



    最近在测试环境的一个Oracle数据库上面,使用exp将表导出没有问题,而将导出的文件使用imp导入时却出现了如下错误。

    IMP-00009: abnormal end of export file	
    Import terminated successfully with warnings.


    经过反复实验,终于找出问题出现的原因,是由以下几点共同造成的:

    a. 数据库中参数deferred_segment_creation设置的是默认值true,即创建表的时候不立即分配段,等有行的时候才会分配段。
    b. 导出的表中有分区表,而恰好该分区表存在分区没有行的情况,即有的分区没有分配段。
    c. 导出时使用了direct=true。


    解决办法直接看(三、解决办法)



    二、问题复现



    1. 准备工作


    在测试库中准备两个用户,tom(导出的用户),jerry(导入的用户),分别给予其最大的权限。

    SQL> create user tom identified by tom;	
    SQL> grant dba to tom;	
    SQL> create user jerry identified by jerry;	
    SQL> grant dba to jerry;


    2. 检查数据库中参数deferred_segment_creation

    SQL> show parameter deferred	
    NAME                                 TYPE        VALUE	
    ------------------------------------ ----------- ------------------------------	
    deferred_segment_creation            boolean     TRUE

    可以看到该参数是true,默认值。


    3. 创建测试表

    SQL> create table tom.t_normal as select * from scott.emp;  // 创建一张普通表,并且有行	
    SQL> create table tom.t_norows as select * from scott.emp where 1=0;  // 创建一张空表	
    SQL> create table tom.t_par(id number, name varchar2(10))	
    partition by list(id)	
    (partition p01 values(1),	
    partition p02 values(default));  // 创建一张分区表,两个分区	
    SQL> insert into tom.t_par values(1, 'aa');  // 往分区p01插入一条数据	
    SQL> commit;


    至此,tom用户下有三张表,t_normal是普通表,t_norows是一张普通的空表,t_par是分区表。


    通过下面的sql查到tom用户下只有两个segment,空表和分区表中无数据的分区都没有创建段。

    SQL> select owner,segment_name,partition_name,segment_type from dba_segments where owner='TOM';	
    OWNER      SEGMENT_NAME         PARTITION_NAME                 SEGMENT_TYPE	
    ---------- -------------------- ------------------------------ ------------------	
    TOM        T_NORMAL                                            TABLE	
    TOM        T_PAR                P01                            TABLE PARTITION

    4. 使用tom对表进行导出


    exp tom/tom file=tom.dmp log=tom_exp.log direct=true


    导出日志如下(省略部分无关内容):

    . . exporting table                       T_NORMAL         14 rows exported	
    . . exporting table                       T_NOROWS          0 rows exported	
    . . exporting table                          T_PAR	
    . . exporting partition                            P01          1 rows exported	
    . . exporting partition                            P02          0 rows exported	
    Export terminated successfully without warnings.


    5. 使用jerry对文件进行导入


    mp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志如下(省略部分无关内容):

    . . importing table                     "T_NORMAL"         14 rows imported	
    . . importing table                     "T_NOROWS"          0 rows imported	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"	
    IMP-00009: abnormal end of export file	
    Import terminated successfully with warnings.


    生产上面出现的错误在这里就得到复现了。而且是在导入"T_PAR":"P02"出现的错误,这个正好印证了前面的观点。



    三、解决办法



    解决办法有以下两种(任一即可):
    a. 使用exp导出的时候不要加direct=true
    b. 设置数据库的参数deferred_segment_creation为false(注意:这个参数只影响新建的分区表,老的分区表导出再导入仍然会报错!)



    四、有时间、有兴趣的读者可以接着做实验



    可能大家会问,你怎么知道是分区表的问题,又怎么知道是direct=true的问题,又怎么知道是参数deferred_segment_creation的问题?接下来我一一验证。


    1. 清空jerry的表,导出tom用户下表t_normal,t_norows,再导入到jerry用户中

    SQL> drop user jerry cascade;  // 通过重建jerry用户来清空jerry的表	
    SQL> create user jerry identified by jerry;	
    SQL> grant dba to jerry;	
    exp tom/tom file=tom.dmp log=tom_exp.log direct=true tables=t_normal,t_norows


    导出日志:

    . . exporting table                       T_NORMAL         14 rows exported	
    . . exporting table                       T_NOROWS          0 rows exported	
    Export terminated successfully without warnings.	
    imp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志:

    . . importing table                     "T_NORMAL"         14 rows imported	
    . . importing table                     "T_NOROWS"          0 rows imported	
    Import terminated successfully without warnings.


    可以看到对这两张表导入是没有问题的


    2. 清空jerry的表,导出tom用户下表t_par,再导入到jerry用户中


    清空jerry的表的操作请看上面的步骤

    exp tom/tom file=tom.dmp log=tom_exp.log direct=true tables=t_par


    导出日志:

    . . exporting table                          T_PAR	
    . . exporting partition                            P01          1 rows exported	
    . . exporting partition                            P02          0 rows exported	
    Export terminated successfully without warnings.	
    	
    imp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志:

    . importing TOM's objects into JERRY	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"	
    IMP-00009: abnormal end of export file	
    Import terminated successfully with warnings.


    可以看到问题就出在对这张分区表的导入上面了


    3. 清空jerry的表,重新导出tom用户下表t_par,再导入到jerry用户中(这次导出不加参数direct=true)


    清空jerry的表的操作请看上面的步骤

    exp tom/tom file=tom.dmp log=tom_exp.log tables=t_par


    导出日志:

    . . exporting table                          T_PAR	
    . . exporting partition                            P01          1 rows exported	
    . . exporting partition                            P02          0 rows exported	
    Export terminated successfully without warnings.	
    	
    imp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志:

    . importing TOM's objects into JERRY	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"          0 rows imported	
    Import terminated successfully without warnings.


    可以看到这次导入没有任何问题,也就是说不加direct=true直接可以解决问题,但是如果我非要加这个参数呢,或者说这个命令写死到程序中了,没办法改怎么办?处理办法看下面第6条。


    4. 清空jerry的表,在tom.t_par的p02分区中插入一条数据,重新导出tom用户下表t_par,再导入到jerry用户中(这次导出依然加参数direct=true)


    清空jerry的表的操作请看上面的步骤

    SQL> insert into tom.t_par values(2, 'bb');  // 往分区p02插入一条数据	
    SQL> commit;


    通过下面的sql查到t_par两个分区都有段了

    SQL> select owner,segment_name,partition_name,segment_type from dba_segments where owner='TOM';	
    	
    OWNER      SEGMENT_NAME         PARTITION_NAME                 SEGMENT_TYPE	
    ---------- -------------------- ------------------------------ ------------------	
    TOM        T_PAR                P01                            TABLE PARTITION	
    TOM        T_PAR                P02                            TABLE PARTITION	
    TOM        T_NORMAL                                            TABLE	
    exp tom/tom file=tom.dmp log=tom_exp.log direct=true tables=t_par

    导出日志:

    . . exporting table                          T_PAR	
    . . exporting partition                            P01          1 rows exported	
    . . exporting partition                            P02          1 rows exported	
    Export terminated successfully without warnings.	
    imp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志:

    . importing TOM's objects into JERRY	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"          1 rows imported	
    Import terminated successfully without warnings.


    可以看到分区表中所有分区都有数据的话,导入就没有任何问题


    5. 验证deferred_segment_creation参数对其的影响


    清空jerry的表的操作请看上面的步骤


    修改数据库中参数deferred_segment_creation为false

    SQL> alter system set deferred_segment_creation=false;


    重建tom用户的t_par表,让其一个分区有数据,另外一个分区无数据

    SQL> drop table tom.t_par;	
    SQL> create table tom.t_par(id number, name varchar2(10))	
    partition by list(id)	
    (partition p01 values(1),	
    partition p02 values(default));  // 创建一张分区表,两个分区	
    SQL> insert into tom.t_par values(1, 'aa');  // 往分区p01插入一条数据	
    SQL> commit;


    通过下面的sql查到t_par两个分区都有段了,即使p02分区里面没有数据

    SQL> select owner,segment_name,partition_name,segment_type from dba_segments where owner='TOM';	
    	
    OWNER      SEGMENT_NAME         PARTITION_NAME                 SEGMENT_TYPE	
    ---------- -------------------- ------------------------------ ------------------	
    TOM        T_PAR                P01                            TABLE PARTITION	
    TOM        T_PAR                P02                            TABLE PARTITION	
    TOM        T_NORMAL                                            TABLE	
    exp tom/tom file=tom.dmp log=tom_exp.log direct=true tables=t_par

     
    导出日志:

    . . exporting table                          T_PAR	
    . . exporting partition                            P01          1 rows exported	
    . . exporting partition                            P02          0 rows exported	
    Export terminated successfully without warnings.	
    imp jerry/jerry file=tom.dmp log=jerry_imp.log fromuser=tom touser=jerry


    导入日志:

    . importing TOM's objects into JERRY	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"          0 rows imported	
    Import terminated successfully without warnings.


    可以看到将参数deferred_segment_creation修改为false导入也正常,但是这只适用于新建的分区表,对于已经存在的分区表,依然会导入失败。处理办法看下面第6条。


    6. 接下来回答上面第3和5步中的问题


    如果想用exp,imp进行导出导入,导出的时候又必须加direct=true,而且导出的表中包含分区表,并且该分区表中存在分区没有段的情况。那怎么办?


    光是将参数deferred_segment_creation修改为false不够,因为这只影响新建的表,要想对老的表也生效,可以采取下面的办法。


    6.1. 将参数deferred_segment_creation修改为false

    SQL> alter system set deferred_segment_creation=false;


    6.2. 使用exp对分区表进行导出(只有那些分区表中存在分区没有分配段的才需要导出),注意不要加direct=true


    exp tom/tom file=tom.dmp log=tom_exp.log tables=t_par


    6.3. 删除该分区表


    SQL> drop table tom.t_par;


    6.4. 使用imp对其进行导入


    imp tom/tom file=tom.dmp log=tom_imp.log full=y


    导入日志

    . importing TOM's objects into TOM	
    . . importing partition                  "T_PAR":"P01"          1 rows imported	
    . . importing partition                  "T_PAR":"P02"          0 rows imported	
    Import terminated successfully without warnings.


    导入后查看段的情况

    SQL> select owner,segment_name,partition_name,segment_type from dba_segments where owner='TOM';	
    	
    OWNER      SEGMENT_NAME         PARTITION_NAME                 SEGMENT_TYPE	
    ---------- -------------------- ------------------------------ ------------------	
    TOM        T_PAR                P02                            TABLE PARTITION	
    TOM        T_PAR                P01                            TABLE PARTITION

    可以看到现在即使P02分区中没有行,也分配了段。这是由于我先前已经将参数deferred_segment_creation设置成了false,并且删除了表,imp在执行过程中,会先创建表然后插入数据,在创建表时,每个分区都会分配段。也就是说只需要解决老的分区表中段没有分配的情况,后面就不会碰到IMP-00009。



    五、总结



    只有在分区表中存在分区没有分配段,而且在导出时使用了direct=true参数,这两种情况在一起才会造成我这个IMP-00009这个错误。对于其它的普通表,不管有没有分配段,是否使用direct=true都不会造成这个错误。


    我在分析IMP-00009这个问题的时候,首先日志纪录只有一行,就写"IMP-00009: abnormal end of export file",第一时间去查导出的日志,"Export terminated successfully without warnings.",导出的日志没有显示任何异常。这就把我整懵逼了。然后我开始求助于万能的互联网,查了一圈下来,没有找到任何解决方案,其实不是大牛不解答,而是问问题的人提供的信息太少了,你就提供个错误日志,比方说我这次碰到的问题,假设你只给个错误日志,大牛打死也复现不出来问题,那就谈不上去解决问题了。而往往当我们把整个问题都描述清楚了,问题大概率就迎刃而解了。


    文章中涉及到的相关信息备注:
    deferred_segment_creation:延迟段创建,上面已经通过实验介绍的很清楚了。
    direct=true:导出数据时不经过buffer cache,这个参数是个天坑,bug极多,导出时尽量不要用。


    出处:https://www.cnblogs.com/ddzj01/


    640?wx_fmt=png

    数据和云

    ID:OraNews

    如有收获,请划至底部,点击“在看”,谢谢!


    资源下载

    关注公众号:数据和云(OraNews)回复关键字获取

    help,30万+下载的完整菜单栏

    2019DTCC,数据库大会PPT

    2018DTCC , 数据库大会PPT

    2018DTC,2018 DTC 大会 PPT

    ENMOBK《Oracle性能优化与诊断案例》

    DBALIFE,“DBA 的一天”海报

    DBA04,DBA 手记4 电子书

    122ARCH,Oracle 12.2体系结构图

    2018OOW,Oracle OpenWorld 资料

    产品推荐

    云和恩墨Bethune Pro2 企业版,集监控、巡检、安全于一身,你的专属数据库实时监控和智能巡检平台,漂亮的不像实力派,你值得拥有!


    640?wx_fmt=jpeg


    云和恩墨zData一体机现已发布超融合版本和精简版,支持各种简化场景部署,零数据丢失备份一体机ZDBM也已发布,欢迎关注。


    640?wx_fmt=jpeg

    云和恩墨大讲堂 | 一个分享交流的地方

    长按,识别二维码,加入万人交流社群


    640?wx_fmt=jpeg

    请备注:云和恩墨大讲堂

  • 相关阅读:
    转载—javascript 设计模式 文章很长,请自备瓜子,水果和眼药水
    js 中call()方法的使用
    上传、下载
    steps1>Struct2配置文件
    页面刷新
    steps1>Struct2控制器组件
    steps1>Struct2概述
    steps1>Struct2基本流程
    steps1>Struct2struts.xml
    steps1>Struct2web.xml
  • 原文地址:https://www.cnblogs.com/hzcya1995/p/13311988.html
Copyright © 2011-2022 走看看