Oracle字符集转换(八):六、如何转换用户实现的字符集(一)

我们来看看用户实现的字符集转换方法。您可以使用 Oracle Utitlity Data Pump Export、Import 检查如何将 KO16MSWIN949、US7ASCII 转换为 AL32UTF8。

对于需要单独实现的方法,Oracle不保证转换,实现者必须保证转换,因此必须通过各种情况的技术验证和测试来验证准确性。

这是上一篇文章的延续。

Oracle 字符集转换(7):5.4。 KO16MSWIN949 环境 CSSCAN 执行结果

6.如何转换用户实现的字符集

6.1.如何应用第三方工具——ETL等

这是一种利用市场上众所周知的ETL工具(如Informatica PowerCenter、IBM DataStage等)实现字符集转换的方法。

这是我没有直接经验的方法,我只知道可以,所以我不会描述详细的方法。

但是,请仅查看以下注意事项。

  • 每个产品都会产生购买成本,或者即使已经购买,也需要额外的开发人工成本。
  • 开源的TOS(Talend Open Studio)-DI、Pentaho Kettle等也可以考虑。
  • 将源DB的数据写入文件,将文件读取插入到目标DB的情况下,列分隔符和行分隔符包含在数据值中,处理一列被压入或一行被压入等错误错误地保存为多行。是绝对必要的
  • 在选择初始工具时,需要在大容量表上进行试点测试以选择合适的工具,确保具有丰富经验的ETL开发人员很重要。

6.2.如何使用 Oracle 实用程序

我们将研究利用 Oracle 函数和实用程序实现字符集转换的三种方法。

1.利用数据泵导出/导入

  • 强制更改字符集:ALTER DATABASE CHARACTER SET INTERNAL
  • 执行导出/导入:应用与目标字符集相同的 NLS_LANG

2. 使用 SQL*Loader

  • 从源数据库卸载数据:SQL*Loader 中可用的格式,PL/SQL、Pro*C、Java 等中需要开发的格式。
  • 使用 SQL*Loader 将数据加载到目标数据库中

3. 使用 DB Link & CTAS & UTL_RAW
(见单独的文章: Oracle字符集转换(九):6.如何转换用户实现的字符集(二))

  • Create DB Link:创建一个从 Target 指向 Source 的 DB Link
  • 视图创建:查看CHAR、VARCHAR2列从source到UTL_RAW.CAST_TO_RAW的转换
  • 将数据加载到 CTAS:在从 Target 到 DB Link 执行 CTAS(Create Table As Select)时应用 UTL_RAW.CAST_TO_VARCHAR2 和 CONVERT 函数

每种方法的优点和缺点总结如下。

方法优点坏处
1.数据泵导出/导入– 可以并行处理
– 不需要换行符、特殊字符、空字符等异常处理
– 需要数据卸载时间
– 如果源数据库是 US7ASCII
  .需要更改字符集(需要保留原件)
  .需要额外转换 CLOB 类型数据
2.SQL*加载器– 可以并行处理– 需要开发创建(卸载)数据文件的功能
– 卸载/加载文件处理过程中需要的异常/错误处理(换行符、特殊字符、空字符等)
– 需要数据卸载时间
3. 数据库链接 & CTAS & UTL_RAW– 无需数据卸载时间– Parallel hint难以并行处理(需要直接划分数据范围进行处理)
– 不适用于超过 2000 字节的数据(RAW 类型的最大长度为 2000 字节)

在查看这些方法时,请考虑以下注意事项:

  • 使用数据泵导出/导入方法从 US7ASCII 转换为 AL32UTF8 时,原始DB的字符集必须用DDL改变
    • 不建议直接更改原始数据库。如果出错,可能很难逆转。
    • 如果已经配置了用于故障转移的数据库,则需要使用它或配置和更改单独的复制数据库。
    • 或者,可以将原始DB的备份数据恢复到单独的服务器上使用。
    • 此外,最好审查配置复制DB的各种方法(磁盘复制等),并选择考虑成本和时间的方法。
    • 如果难以配置复制DB,可以在完全备份后执行,但如果需要恢复,服务停机时间可能会很长,具体取决于数据量。
  • 除非停止服务,无论采用哪种方法,都必须匹配从原始DB中提取的点,以保证数据的一致性(使用FLASHBACK_SCN、FLASHBACK_TIME)
  • 另外,必须提前测试和准备提取点后反映变化数据的方法(使用CDC等)

6.2.1.方法 1) 数据泵导出/导入

准备工作:使用以下脚本创建目录对象并授予执行Data Pump Export/Import时所需的权限。 

为每个要测试的 Oracle 实例执行:ORAUS7、ORAMSWIN949 和 ORAUTF。

▼ 为 ORAUS7 实例授予权限

-- ORAUS7 instance에 권한 부여
title ORAUS7
set NLS_LANG=AMERICAN_AMERICA.US7ASCII
sqlplus sys/________@oraus7 as sysdba
CREATE OR REPLACE DIRECTORY PUMP_DIR AS 'D:\Temp\datapump';
GRANT READ, WRITE ON DIRECTORY PUMP_DIR TO LEG;
EXIT

▼ 授予 ORAMSWIN949 实例权限

-- ORAMSWIN949 instance에 권한 부여
title ORAMSWIN949
set NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
sqlplus sys/________@oramswin949 as sysdba
CREATE OR REPLACE DIRECTORY PUMP_DIR AS 'D:\Temp\datapump';
GRANT READ, WRITE ON DIRECTORY PUMP_DIR TO LEG;
EXIT

▼ 授权ORAUTF实例

-- ORAUTF instance에 권한 부여
title ORAUTF
set NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
sqlplus sys/________@orautf as sysdba
CREATE OR REPLACE DIRECTORY PUMP_DIR AS 'D:\Temp\datapump';
GRANT READ, WRITE ON DIRECTORY PUMP_DIR TO LEG;
EXIT

让我们分别看看以下三种情况。

  1. KO16MSWIN949 到 AL32UTF8
  2. US7ASCII 到 AL32UTF8(2 条路径)
  3. US7ASCII 到 AL32UTF8(1 条路径)

作为参考,在US7ASCII到AL32UTF8转换的情况下,CLOB类型的列不能正常转换,所以需要单独处理。

将在下一篇文章中解释。

1. KO16MSWIN949 到 AL32UTF8

1. KO16MSWIN949 to AL32UTF8 개념도
1. KO16MSWIN949转AL32UTF8概念图

在这种情况下,CHAR、VARCHAR2 和 CLOB 类型都正常转换。

每个步骤的执行脚本如下。

--------------------------------------------------------------------
-- 단계1
-- 실행 Instance: ORAMSWIN949
-- NLS_LANG: KO16MSWIN949
-- 작업명: Datapump Export
-- Tool: expdp

set NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
expdp leg/leg@oramswin949 directory=PUMP_DIR dumpfile=oramswin949_leg.dmp logfile=oramswin949_leg_exp.log schemas=leg


--------------------------------------------------------------------
-- 단계2
-- 실행 Instance: ORAUTF
-- NLS_LANG: KO16MSWIN949
-- 작업명: Table 생성
-- Tool: SQL*Plus

-- Target table을 미리 생성
-- LINE_NUM, SUB_STA_NM 컬럼 길이 증가
-- COMMT 컬럼 데이터 타입 변경(VARCHAR2 -> CLOB)
CREATE TABLE SUB_MON_STAT 
(
     USE_MON            VARCHAR2(8),
     LINE_NUM           VARCHAR2(50),  -- 14 -> 50
     SUB_STA_ID         VARCHAR2(4),
     SUB_STA_NM         VARCHAR2(100), -- 20 -> 100
     RIDE_PASGR_NUM     NUMBER(10),
     ALIGHT_PASGR_NUM   NUMBER(10),
     WORK_DT            VARCHAR2(8),
     COMMT              CLOB,          -- VARCHAR2 -> CLOB
     REF_DES            CLOB,
     REF_IMG            BLOB
);


--------------------------------------------------------------------
-- 단계3
-- 실행 Instance: ORAUTF
-- NLS_LANG: KO16MSWIN949
-- 작업명: Datapump Import
-- Tool: impdp
set NLS_LANG=AMERICAN_AMERICA.KO16MSWIN949
impdp leg/leg@orautf directory=PUMP_DIR dumpfile= oramswin949_leg.dmp logfile=orautf_leg_imp.log content=data_only

2. US7ASCII 到 AL32UTF8(2 条路径)

2. US7ASCII to AL32UTF8 (2 path) 개념도
2. US7ASCII转AL32UTF8(2路)概念图

请注意以下事项:

  • 临时复制DB服务器是以与原始相同的形式复制As-Is操作DB的DB。
  • 测试环境中使用ORAMSWIN949实例作为临时复制DB,使用Data Pump复制数据,此时复制前必须将Character Set改为US7ASCII。
  • 在实际应用中,最好单独配置使用US7ASCII字符集的临时复制DB服务器。

这种方法ORACLE不推荐,需要单独进行转换处理,因为CLOB类型的数据一般不会转换。

每个步骤的执行脚本如下。

--------------------------------------------------------------------
-- 단계1-1
-- 실행 Instance: ORAUS7
-- NLS_LANG: US7ASCII
-- 작업명: Datapump Export
-- Tool: expdp
set NLS_LANG=US7ASCII
expdp leg/leg@oraus7 directory=MIG_DIR dumpfile=oraus7_leg_exp.dmp logfile=oraus7_leg_exp.log schemas=leg


--------------------------------------------------------------------
-- 단계1-2
-- 실행 Instance: ORAMSWIN949
-- NLS_LANG: US7ASCII
-- 작업명: Datapump Import
-- Tool: impdp
set NLS_LANG=US7ASCII
impdp leg/leg@oramswin949 directory= MIG_DIR dumpfile=oramswin949_leg_exp.dmp logfile=oramswin949_leg_imp.log


--------------------------------------------------------------------
-- 단계2
-- 실행 Instance: ORAMSWIN949
-- NLS_LANG: US7ASCII
-- 작업명: Character Set 변경
-- Tool: SQL*Plus
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER SYSTEM ENABLE RESTRICTED SESSION;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
ALTER SYSTEM SET AQ_TM_PROCESSES=0;
ALTER DATABASE OPEN;
ALTER DATABASE CHARACTER SET INTERNAL_USE KO16MSWIN949;
SHUTDOWN IMMEDIATE;
STARTUP;


--------------------------------------------------------------------
-- 단계3
-- 실행 Instance: ORAMSWIN949
-- NLS_LANG: KO16MSWIN949
-- 작업명: Datapump Export
-- Tool: expdp
-- sql*plus에서 한글 표시 되는지 확인 후 다음 실행
set NLS_LANG=KO16MSWIN949
expdp leg/leg@oramswin949 directory=MIG_DIR dumpfile=oramswin949_leg_exp.dmp logfile=oramswin949_leg_exp.log schemas=leg


--------------------------------------------------------------------
-- 단계4
-- 실행 Instance: ORAUTF
-- NLS_LANG: AL32UTF8
-- 작업명: Table 생성
-- Tool: SQL*Plus

-- Target table을 미리 생성
-- LINE_NUM, SUB_STA_NM 컬럼 길이 증가
-- COMMT 컬럼 데이터 타입 변경(VARCHAR2 -> CLOB)
CREATE TABLE SUB_MON_STAT 
(
     USE_MON            VARCHAR2(8),
     LINE_NUM           VARCHAR2(50),  -- 14 -> 50
     SUB_STA_ID         VARCHAR2(4),
     SUB_STA_NM         VARCHAR2(100), -- 20 -> 100
     RIDE_PASGR_NUM     NUMBER(10),
     ALIGHT_PASGR_NUM   NUMBER(10),
     WORK_DT            VARCHAR2(8),
     COMMT              CLOB,          -- VARCHAR2 -> CLOB
     REF_DES            CLOB,
     REF_IMG            BLOB
);


--------------------------------------------------------------------
-- 단계5
-- 실행 Instance: ORAUTF
-- NLS_LANG: AL32UTF8
-- 작업명: Datapump Import
-- Tool: impdp
impdp leg/leg@orautf directory=MIG_DIR dumpfile=oramswin949_leg_exp.dmp logfile=oramswin949_leg_imp.log content=data_only

3. US7ASCII 到 AL32UTF8 (1 路径)

3. US7ASCII to AL32UTF8 (1 path) 개념도
3. US7ASCII转AL32UTF8(1路)概念图

这种方法ORACLE不推荐,需要单独进行转换处理,因为CLOB类型的数据一般不会转换。

另外,由于改变了运行DB的字符集,无法保留原来的数据,出错后难以回滚,所以尽量不要应用到运行环境中。

如果您不可避免地使用该方法,请在测试环境中充分验证后应用到生产环境中。

每个步骤的执行脚本如下。

--------------------------------------------------------------------
-- 단계1
-- 실행 Instance: ORAUS7
-- NLS_LANG: US7ASCII
-- 작업명: Character Set 변경
-- Tool: SQL*Plus
SHUTDOWN IMMEDIATE;
STARTUP MOUNT;
ALTER SYSTEM ENABLE RESTRICTED SESSION;
ALTER SYSTEM SET JOB_QUEUE_PROCESSES=0;
ALTER SYSTEM SET AQ_TM_PROCESSES=0;
ALTER DATABASE OPEN;
ALTER DATABASE CHARACTER SET INTERNAL_USE KO16MSWIN949;
SHUTDOWN IMMEDIATE;
STARTUP;


--------------------------------------------------------------------
-- 단계2
-- 실행 Instance: ORAMSWIN949(=ORAUS7)
-- NLS_LANG: KO16MSWIN949
-- 작업명: Datapump Export
-- Tool: expdp
-- sql*plus에서 한글 표시 되는지 확인 후 다음 실행
set NLS_LANG=KO16MSWIN949
expdp leg/leg@oramswin949 directory=MIG_DIR dumpfile=oramswin949_leg_exp.dmp logfile=oramswin949_leg_exp.log schemas=leg


--------------------------------------------------------------------
-- 단계3
-- 실행 Instance: ORAUTF
-- NLS_LANG: AL32UTF8
-- 작업명: Table 생성
-- Tool: SQL*Plus

-- Target table을 미리 생성
-- LINE_NUM, SUB_STA_NM 컬럼 길이 증가
-- COMMT 컬럼 데이터 타입 변경(VARCHAR2 -> CLOB)
CREATE TABLE SUB_MON_STAT 
(
     USE_MON            VARCHAR2(8),
     LINE_NUM           VARCHAR2(50),  -- 14 -> 50
     SUB_STA_ID         VARCHAR2(4),
     SUB_STA_NM         VARCHAR2(100), -- 20 -> 100
     RIDE_PASGR_NUM     NUMBER(10),
     ALIGHT_PASGR_NUM   NUMBER(10),
     WORK_DT            VARCHAR2(8),
     COMMT              CLOB,          -- VARCHAR2 -> CLOB
     REF_DES            CLOB,
     REF_IMG            BLOB
);


--------------------------------------------------------------------
-- 단계4
-- 실행 Instance: ORAUTF
-- NLS_LANG: AL32UTF8
-- 작업명: Datapump Import
-- Tool: impdp
impdp leg/leg@orautf directory=MIG_DIR dumpfile=oramswin949_leg_exp.dmp logfile=oramswin949_leg_imp.log content=data_only

6.2.2.方法二)SQL*Loader

SQL*Loader 需要一个控制文件和一个数据文件。其中,数据文件包含实际数据。

要创建这个数据文件,可以使用PL/SQL、Pro*C、Java等各种工具自己创建,也可以直接参考已经实现相同功能的源码直接使用,也可以稍作扩展它。

这里不直接介绍如何制作,只介绍实现源码的网址。

Effective Oracle 的作者 Tom Kyte 的博客: https://asktom.oracle.com/Misc/httpasktomoraclecomtkyteflat.html

另外,如果你在谷歌上搜索,你会找到你可以参考的源代码。

以表或分区为单位创建数据文件后,在多个组中同时执行sqlldr以并行加载它们,以在适当的负载水平下最小化执行时间。

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

zh_CN简体中文