在使用exp/imp导出导入,经常会碰见各种的问题,前两天某公众号发了篇《IMP-00009:异常结束导出文件解决方案》,介绍了导入出现IMP-00009错误的解决方案,讲了各种场景,可以参考。
曾经写过的一些和导入导出相关的文章,
《解决导入过程中出现的ORA-02289错误》
《Oracle导入导出的常见错误》
《生产数据导入测试环境碰见的一些问题》
《imp/exp导入导出的一些错误》
《使用exp导出报错EXP-00091》
前两天,从自己的笔记本,Windows环境,负责将远程测试库某个用户的表结构导入另外一个测试库用户的时候,碰见了几个问题。
问题1,
这个错误主要是因为笔记本的操作系统字符集和数据库的字符集不一致导致,但好像对imp导入,是无影响的,
D:\>exp user/passwd file=d:\user.dmp rows=nExport: Release 10.2.0.3.0 - Production on 星期二 8月 6 15:49:59 2019Copyright (c) 1982, 2005, Oracle. All rights reserved.连接到: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit ProductionWith the Partitioning, OLAP, Data Mining and Real Application Testing options已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集服务器使用 AL32UTF8 字符集 (可能的字符集转换)注: 将不导出表数据 (行)即将导出指定的用户.... 正在导出 pre-schema 过程对象和操作. 正在导出用户 USER 的外部函数库名. 导出 PUBLIC 类型同义词. 正在导出专用类型同义词. 正在导出用户 DEP 的对象类型定义即将导出 USER 的对象.... 正在导出数据库链接. 正在导出序号. 正在导出簇定义. 即将导出 DEP 的表通过常规路径.... . 正在导出表 TBLEXP-00091: 正在导出有问题的统计信息。EXP-00091: 正在导出有问题的统计信息。...
Export: Release 10.2.0.3.0 - Production on 星期二 8月 6 15:49:59 2019
Copyright (c) 1982, 2005, Oracle. All rights reserved.
连接到: Oracle Database 11g Enterprise Edition Release 11.2.0.4.0 - 64bit Produc
tion
With the Partitioning, OLAP, Data Mining and Real Application Testing options
已导出 ZHS16GBK 字符集和 AL16UTF16 NCHAR 字符集
服务器使用 AL32UTF8 字符集 (可能的字符集转换)
注: 将不导出表数据 (行)
即将导出指定的用户...
. 正在导出 pre-schema 过程对象和操作
. 正在导出用户 USER 的外部函数库名
. 导出 PUBLIC 类型同义词
. 正在导出专用类型同义词
. 正在导出用户 DEP 的对象类型定义
即将导出 USER 的对象...
. 正在导出数据库链接
. 正在导出序号
. 正在导出簇定义
. 即将导出 DEP 的表通过常规路径...
. . 正在导出表 TBL
EXP-00091: 正在导出有问题的统计信息。
EXP-00091: 正在导出有问题的统计信息。
...
如果看着不爽,可以改字符集,
1. 查看数据库的字符集,
SQL> select userenv('language') from dual;USERENV('LANGUAGE')--------------------------------------------SIMPLIFIED CHINESE_CHINA.AL32UTF8
USERENV('LANGUAGE')
--------------------------------------------
SIMPLIFIED CHINESE_CHINA.AL32UTF8
用这三条语句,是等价的检索,
select * from v$nls_parameters where parameter='NLS_CHARACTERSET';select * from nls_database_parameters t where t.parameter='NLS_CHARACTERSET'select * from v$nls_parameters where parameter='NLS_CHARACTERSET';from v$nls_parameters where parameter='NLS_CHARACTERSET';
select * from nls_database_parameters t where t.parameter='NLS_CHARACTERSET'
select * from v$nls_parameters where parameter='NLS_CHARACTERSET';
2. 设置笔记本的字符集,
如果用的Linux环境,
export NLS_LANG=SIMPLIFIED CHINESE_CHINA.AL32UTF8
如果用的Windows环境,
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.AL32UTF8
exp的时候,不会报错,但是显示成乱码,
这个不影响导出,导出完成再设置字符集为,
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.ZHS16GBK
补充下字符集的知识,
NLS_LANG = language_territory.charset
包含三个组成部分,即语言、地域和字符集,每个部分控制了NLS子集的特性, Language指定服务器消息的语言, territory指定服务器的日期和数字格式, charset指定字符集。
从NLS_LANG的组成我们可以看出,真正影响数据库字符集的其实是第三部分。所以两个数据库之间的字符集只要第三部分一样就可以相互导入导出数据,前面影响的只是提示信息是中文还是英文。
问题2,
exp导出的表不全,一种可能的原因,就是导出的用户表可能存在空数据表,在11g下因为延迟段分配的特性,该表不会分配任何的Extent,导出的时候,就会出现此异常。
查看延迟段分配特性是否开启,true为开启,false为关闭,
SQL> show parameter deferred_segment_creation; show parameter deferred_segment_creation;
如果为开启,可以设置该参数,为false,关闭延迟段分配,
SQL> alter system set deferred_segment_creation=false; alter system set deferred_segment_creation=false;
但是要注意,此时仅对新建的表是有效的,旧表的Extent还是未创建,
SQL> create table a01 (id number);Table created.SQL> select table_name, segment_created from user_tables where table_name = 'A01';TABLE_NAME SEGMENT_C-------------- --------------A01 NOSQL> alter system set deferred_segment_creation=false;System altered.SQL> create table a02 (id number);Table created.SQL> select table_name, segment_created from user_tables where table_name = 'A01' or table_name = 'A02';TABLE_NAME SEGMENT_C-------------- -------------A01 NOA02 YES
Table created.
SQL> select table_name, segment_created from user_tables where table_name = 'A01';
TABLE_NAME SEGMENT_C
-------------- --------------
A01 NO
SQL> alter system set deferred_segment_creation=false;
System altered.
SQL> create table a02 (id number);
Table created.
SQL> select table_name, segment_created from user_tables where table_name = 'A01' or table_name = 'A02';
TABLE_NAME SEGMENT_C
-------------- -------------
A01 NO
A02 YES
此时,可以针对数据表、索引、物化视图等手工分配Extent,看到一种方法,就是利用user_tables,将记录数为0的表,检索出来拼出手工分配Extent的SQL语句,
SQL> select 'alter table '||table_name||' allocate extent;' from user_tbles where num_rows=0;' allocate extent;' from user_tbles where num_rows=0;
但是这种做法,我觉得可能不很准确,如果按照segment_created字段,就会挑出来未分配任何Extent的表,进行拼接SQL,手工分配Extent,
SQL> select 'alter table '||table_name||' allocate extent;' from user_tables where segment_created = 'NO';'ALTERTABLE'||TABLE_NAME||'ALLOCATEEXTENT;'----------------------------------------------alter table A01 allocate extent;||table_name||' allocate extent;' from user_tables where segment_created = 'NO';
'ALTERTABLE'||TABLE_NAME||'ALLOCATEEXTENT;'
----------------------------------------------
alter table A01 allocate extent;
直接执行结果,就会保证所有待导出的表,都会分配了Extent了。
其实导入导出的问题,和数据库安装的问题(《数据库安装的两个小错误》),都是要积累的,碰见的问题多了,记住的多了,这就不是问题了。