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
让我们分别看看以下三种情况。
- KO16MSWIN949 到 AL32UTF8
- US7ASCII 到 AL32UTF8(2 条路径)
- US7ASCII 到 AL32UTF8(1 条路径)
作为参考,在US7ASCII到AL32UTF8转换的情况下,CLOB类型的列不能正常转换,所以需要单独处理。
将在下一篇文章中解释。
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 条路径)
请注意以下事项:
- 临时复制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 路径)
这种方法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以并行加载它们,以在适当的负载水平下最小化执行时间。