您的位置:首页 > 其它

分析ORA-12899, 迁移数据时遇到的多字节问题

2013-03-26 14:56 344 查看

一,背景回顾:

手头有一个同事使用exp导出的dump文件,我用其导入自己的测试环境时,有一小部分数据遇到ORA-12899而不能被导入。

源数据库字符集: ZHS16GBK

exp客户端NLS_LANG: SIMPLIFIED CHINESE_CHINA.ZHS16GBK

目标数据库字符集: AL32UTF8

二,实验重演:

创建测试库A,使用字符集 ZHS16GBK (test4)

创建测试库B,使用字符集 AL32UTF8 (test3)

然后使用exp imp,expdp impdp做测试

在本例中,为了避免字符集转换,需要设定正确的NLS_LANG

Setp1. 在ZHS16BGK数据库创建测试表及数据

库A:

[oracle@redhat ~]$ export ORACLE_SID=test4

[oracle@redhat ~]$ export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"
[oracle@redhat ~]$ sqlplus pjh/123

SQL*Plus: Release 11.2.0.3.0 Production on 星期二 3月 26 13:17:28 2013

Copyright (c) 1982, 2011, Oracle. All rights reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET';

PARAMETER VALUE

---------------------------------------------------------------- ----------------------------------------------------------------

NLS_CHARACTERSET ZHS16GBK

SQL> show user

USER is "PJH"

SQL> create table test1 (id number, name varchar2(8));

Table created.

SQL> insert into test1 values (1,'我');

1 row created.

SQL> insert into test1 values (2,'我是');

1 row created.

SQL> insert into test1 values (3,'我是谁');

1 row created.

SQL> insert into test1 values (4,'我是a');

1 row created.

SQL> commit;

Commit complete.

SQL> select * from test1;

ID NAME

---------- ---------------

1 我

2 我是

3 我是谁

4 我是a

Step2. 分别使用exp 与 expdp导出test1表,供后续导入使用

使用exp导出:

[oracle@redhat ~]$ export ORACLE_SID=test4

[oracle@redhat ~]$ export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"

[oracle@redhat ~]$ exp system/oracle file=/tmp/test1.dump tables=pjh.test1

Export: Release 11.2.0.3.0 - Production on 星期二 3月 26 13:40:53 2013

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

Export done in ZHS16GBK character set and AL16UTF16 NCHAR character set

About to export specified tables via Conventional Path ...

Current user changed to PJH

. . exporting table TEST1 4 rows exported

Export terminated successfully without warnings.

[oracle@redhat ~]$

使用expdp导出:

[oracle@redhat ~]$ export ORACLE_SID=test4

[oracle@redhat ~]$ export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"

[oracle@redhat ~]$ expdp pjh/123 dumpfile=test1.dp directory=dp_tmp job_name=pjh1

Export: Release 11.2.0.3.0 - Production on 星期二 3月 26 13:37:59 2013

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

启动 "PJH"."PJH1": pjh/******** dumpfile=test1.dp directory=dp_tmp job_name=pjh1

正在使用 BLOCKS 方法进行估计...

处理对象类型 SCHEMA_EXPORT/TABLE/TABLE_DATA

使用 BLOCKS 方法的总估计: 64 KB

处理对象类型 SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA

处理对象类型 SCHEMA_EXPORT/TABLE/TABLE

处理对象类型 SCHEMA_EXPORT/TABLE/COMMENT

处理对象类型 SCHEMA_EXPORT/TABLE/INDEX/INDEX

处理对象类型 SCHEMA_EXPORT/TABLE/CONSTRAINT/CONSTRAINT

处理对象类型 SCHEMA_EXPORT/TABLE/INDEX/STATISTICS/INDEX_STATISTICS

. . 导出了 "PJH"."TEST1" 5.445 KB 4 行

已成功加载/卸载了主表 "PJH"."PJH1"

******************************************************************************

PJH.PJH1 的转储文件集为:

/tmp/test1.dp

作业 "PJH"."PJH1" 已于 13:39:05 成功完成

[oracle@redhat ~]$

Step3. 分别使用imp与impdp将test1导入AL32UTF8的数据库

库B:

SQL> select * from v$nls_parameters where parameter='NLS_CHARACTERSET';

PARAMETER VALUE

---------------------------------------------------------------- ----------------------------------------------------------------

NLS_CHARACTERSET AL32UTF8

SQL> create user pjh identified by "123";

User created.

SQL> grant connect,resource to pjh;

Grant succeeded.

SQL>

使用imp导入:

[oracle@redhat ~]$ export ORACLE_SID=test3

[oracle@redhat ~]$ export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"

[oracle@redhat ~]$ imp system/oracle file=/tmp/test1.dump fromuser=pjh touser=pjh

Import: Release 11.2.0.3.0 - Production on 星期二 3月 26 13:59:07 2013

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

Export file created by EXPORT:V11.02.00 via conventional path

import done in ZHS16GBK character set and AL16UTF16 NCHAR character set

import server uses AL32UTF8 character set (possible charset conversion)

. importing PJH's objects into PJH

. . importing table "TEST1"

IMP-00019: row rejected due to ORACLE error 12899

IMP-00003: ORACLE error 12899 encountered

ORA-12899: 列 "PJH"."TEST1"."NAME" 的值太大 (实际值: 9, 最大值: 8)

Column 1 3

Column 2 我是谁 3 rows imported

Import terminated successfully with warnings.

[oracle@redhat ~]$

[oracle@redhat ~]$ sqlplus pjh/123

SQL*Plus: Release 11.2.0.3.0 Production on 星期二 3月 26 13:59:59 2013

Copyright (c) 1982, 2011, Oracle. All rights reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select * from test1;

ID NAME

---------- ----------------

1 我

2 我是

4 我是a

尝试用impdp导入:

[oracle@redhat ~]$ export ORACLE_SID=test3

[oracle@redhat ~]$ export NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK"

[oracle@redhat ~]$ impdp pjh/123 dumpfile=test1.dp directory=dp_tmp job_name=pjh1

Import: Release 11.2.0.3.0 - Production on 星期二 3月 26 14:03:11 2013

Copyright (c) 1982, 2011, Oracle and/or its affiliates. All rights reserved.

Connected to: Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

已成功加载/卸载了主表 "PJH"."PJH1"

启动 "PJH"."PJH1": pjh/******** dumpfile=test1.dp directory=dp_tmp job_name=pjh1

处理对象类型 SCHEMA_EXPORT/PRE_SCHEMA/PROCACT_SCHEMA

处理对象类型 SCHEMA_EXPORT/TABLE/TABLE

处理对象类型 SCHEMA_EXPORT/TABLE/TABLE_DATA

ORA-02374: conversion error loading table "PJH"."TEST1"

ORA-12899: value too large for column NAME (actual: 9, maximum: 8)

ORA-02372: data for row: NAME : 0X'CED2CAC7CBAD'

. . 导入的 "PJH"."TEST1" 5.445 KB 3 用完了 4 行

作业 "PJH"."PJH1" 已于 14:03:19 成功完成

[oracle@redhat ~]$ sqlplus pjh/123

SQL*Plus: Release 11.2.0.3.0 Production on 星期二 3月 26 14:03:34 2013

Copyright (c) 1982, 2011, Oracle. All rights reserved.

Connected to:

Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> select * from test1;

ID NAME

---------- ----------------

1 我

2 我是

4 我是a

第三行同样导入失败! exp与expdp均有此问题。

三,原因分析:

一个汉字(包括中文标点、符号)在不同字符集的数据库中占用的字节数是不同的。

在ZHs16GBK的数据库中,一个汉字占用2个字节,但是在AL32UTF8数据库中,一个汉字占用3个字节。

本例中 ZHS16GBK数据库中test1表的name字段长度是8个字节。 导入到AL32UTF8数据库时,表的定义不会改变,即name字段仍然是8个字节。 但是在AL32UTF8中8个字节不能够保存下3个汉字。

以下可以非常直观的看到区别:

在ZHS16GBK数据库中

SQL> select dump('我是谁',1106) from dual;

DUMP('我是谁',1106)

-----------------------------------------------------

Typ=96 Len=6 CharacterSet=ZHS16GBK: ce,d2,ca,c7,cb,ad

在AL32UFT8数据库中

SQL> select dump('我是谁',1106) from dual;

DUMP('我是谁',1106)

--------------------------------------------------------------------------------

Typ=96 Len=9 CharacterSet=AL32UTF8: e6,88,91,e6,98,af,e8,b0,81

当然为了输入中文,在环境变量设置 NLS_LANG="SIMPLIFIED CHINESE_CHINA.ZHS16GBK" 是必须的!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: