工具 & 效率17 分钟阅读
Oracle 修改数据库字符集大法 - DMU 工具
大家好,这里是公众号 DBA学习之路,分享一些学习数据库路上的知识和经验。 @TOC目录 上篇说到 甩锅篇:Oracle 数据库特殊字符 ™ 乱码问题https://www.modb.pro/db/18913066532
2025年2月21日阅读—点赞—收藏—
oraclerac
在知识库中专注阅读,并随时返回相关工具与课程
大家好,这里是公众号 DBA学习之路,分享一些学习数据库路上的知识和经验。 @TOC目录 上篇说到 甩锅篇:Oracle 数据库特殊字符 ™ 乱码问题https://www.modb.pro/db/18913066532
大家好,这里是公众号 DBA学习之路,分享一些学习数据库路上的知识和经验。

本章目标:掌握本章核心知识点 前置要求:完成前序章节学习 预计时长:60 分钟
上篇说到 甩锅篇:Oracle 数据库特殊字符 ™ 乱码问题,最后结论是客户端字符集设置有问题,但是开发不认,硬说建库时选错字符集了,要修改数据库字符集为 AL32UTF8,那会儿咋不说!
最后,拗不过还是要改,先测试环境测试一下修改过程吧,本次使用 DMU 工具修改数据库字符集为 AL32UTF8。
DMU 是 Unicode 数据库迁移助手,能够将现有数据库的 NLS_CHARACTERSET 转换为 AL32UTF8 或 UTF8。DMU 基于图形用户界面的工具,比 csscan/csalter 更加直观,并能在将 Oracle 数据库字符集更改为 UTF8 或 AL32UTF8 时,自动化许多转换过程。
DMU 还可用于验证现有 AL32UTF8/UTF8 数据库中的数据,并且如果需要,还可更正由于客户端配置不正确而未以 AL32UTF8/UTF8 编码存储的 UTF8/AL32UTF8 数据库中的数据。
从 DMU 1.2 开始,DMU 还可用于(有限制)更正数据库 NLS_CHARACTERSET。DMU 的当前版本是 DMU 23.1,于 2024 年 6 月发布。

此版本中的新功能亮点包括:
当数据库版本大于 11.2.0.3 版本,使用 DMU 只需要安装 SYS.DBMS_DUMA_INTERNAL 包,该包需要使用 sys 用户运行 $?/rdbms/admin/prvtdumi.plb 来创建:
1SQL> conn / as sysdba2Connected.3SQL> @?/rdbms/admin/prvtdumi.plb45Library created.678Package created.910No errors.1112Package body created.1314No errors.如果数据库版本低于 11.2.0.3,使用 DMU 需要在服务器端提前安装补丁 9825461。
对于 DMU 不支持的版本/平台,使用 Csscan & Csalter 或者 Csscan & Export/import 是转为 AL32UTF8 的唯一方法。
如果数据库版本大于 12.1.0.2,在安装数据库软件时,会默认自带安装 DMU 2.0 客户端(用户界面):

在 ORACLE_HOME 目录下可以找到 dmu 的安装目录:
1[oracle@orcl19c:/home/oracle]$ ll $ORACLE_HOME/dmu2总用量 203drwxr-xr-x. 2 oracle oinstall 37 4月 17 2019 configuration4drwxr-xr-x. 9 oracle oinstall 100 4月 17 2019 dmu5-rw-r--r--. 1 oracle oinstall 238 7月 13 2017 dmucls.sh6-rw-r--r--. 1 oracle oinstall 53 7月 19 2012 dmu.sh7drwxr-xr-x. 2 oracle oinstall 24 4月 17 2019 dropins8drwxr-xr-x. 2 oracle oinstall 60 4月 17 2019 equinox9drwxr-xr-x. 2 oracle oinstall 4096 4月 17 2019 external10drwxr-xr-x. 8 oracle oinstall 85 4月 17 2019 ide11drwxr-xr-x. 6 oracle oinstall 57 4月 17 2019 jdev12drwxr-xr-x. 2 oracle oinstall 4096 4月 17 2019 jlib13drwxr-xr-x. 10 oracle oinstall 4096 4月 17 2019 modules14drwxr-xr-x. 5 oracle oinstall 50 4月 17 2019 netbeans15drwxr-xr-x. 3 oracle oinstall 23 4月 17 2019 sleepycat建议下载最新的 DMU 版本,解压替换默认 DMU:
1[root@orcl19c:/soft]# chown oracle:oinstall /soft/p36716892_2310_Generic.zip 2[root@orcl19c:/soft]# su - oracle3[oracle@orcl19c:/home/oracle]$ cd /soft/4[oracle@orcl19c:/soft]$ unzip -qo p36716892_2310_Generic.zip -d $ORACLE_HOME5[oracle@orcl19c:/soft]$ cd $ORACLE_HOME/dmu6[oracle@orcl19c:/u01/app/oracle/product/19.3.0/db/dmu]$ sh dmu.sh必须使用图形化界面打开 DMU 工具:


初始化界面如下:

到这就算启动成功了。
为了测试数据完整,这里可以创建一个测试表,插入一些测试数据:
1SQL> create user lucifer identified by oracle;2SQL> grant dba to lucifer;34SQL> conn lucifer/oracle56SQL> CREATE TABLE test_conversion (7 id NUMBER PRIMARY KEY,8 char_data VARCHAR2(4000),9 clob_data CLOB, 10 description VARCHAR2(500),11 mixed_content VARCHAR2(4000)12);1314SQL> INSERT INTO test_conversion (id, char_data, clob_data, description, mixed_content)15VALUES (1, NULL, '这是一个包含中文字符的CLOB字段', '描述:包含中文字符的CLOB字段', NULL);1617SQL> INSERT INTO test_conversion (id, char_data, clob_data, description, mixed_content)18VALUES (2, 'This is a CHAR field containing English characters.', NULL, 'Description: CHAR field with English characters', NULL);1920SQL> INSERT INTO test_conversion (id, char_data, clob_data, description, mixed_content)21VALUES (3, NULL, '包含特殊字符的CLOB字段:$#@!&*()', 'Description: CLOB field with special characters', NULL);2223SQL> INSERT INTO test_conversion (id, char_data, clob_data, description, mixed_content)24VALUES (4, NULL, '包含表情符号的CLOB字段:😊😂👍 ', 'Description: CLOB field with emojis', NULL);2526SQL> INSERT INTO test_conversion (id, char_data, clob_data, description, mixed_content)27VALUES (5, '混合内容的字符字段:Hello,世界!1234 @#$%', NULL, 'Description: Mixed content CHAR field', '混合内容的CLOB字段:Hello,世界!1234 @#$%');2829SQL> commit;3031SQL> set line2222 pages1000 wrap off tab off32col char_data for a8033col clob_data for a8034col description for a8035col mixed_content for a8036select * from lucifer.test_conversion order by id;
📢 注意:这里有几个字符是 GBK 不支持的,所以显示乱码。
测试数据创建完成后下面就开始转换字符集。
首先连接需要转换字符集的数据库:
📢注意:在正式进行数据库字符集转换之前,建议对数据库进行全备,确保数据库可以正常恢复。

填写数据库连接信息,点击测试连接:

确保能够正常连接,保存即可。
双击打开刚保存的连接:

选择我们需要转换的数据库字符集:AL32UTF8

这里我选择 SYSAUX 表空间,大家也可以单独创建一个表空间:

点击完成:

等待一会儿,会提示安装完成:

可以看到转换字符集一共需要 4 步,目前已经完成第一步:

第二步需要扫描数据库,点击链接即可跳转:

配置一些参数用于扫描数据库,可根据实际情况进行配置:

选择需要扫描的用户:

点击下一步:

默认全部转换:

等待扫描完成(扫描时间取决于数据库对象数量以及大小):

扫描完成,这里显示有一些有问题的对象,可以通过 scan report 查看:

检查是否存在会转换失败的对象:

参考 Tips For and Known Issues With The Database Migration Assistant for Unicode (DMU) Tool version (Doc ID 2018250.1) 文档,检查 SYS.SOURCE$ 对象扫描问题:

1SQL> set line2222 pages10002col owner for a103col object_name for a304col object_type for a205SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM dba_objects WHERE OBJECT_ID IN6(SELECT UNIQUE obj# FROM sys.source$ WHERE rowid IN7(SELECT row_id FROM system.dum$exceptions WHERE obj# =8( select OBJECT_ID FROM dba_objects where OWNER='SYS' AND OBJECT_NAME ='SOURCE$')9and TYPE ='8'))10ORDER BY owner;1112OWNER OBJECT_NAME OBJECT_TYPE13---------- ------------------------------ --------------------14SYS INSERT_DATA_TO_TEST_TABLE PROCEDURE对了,这个是我之前测试数据的时候创建的一个存储过程,不符合要求:

很简单,将这个存储过程删除或者移动到其他用户下即可:
1SQL> drop procedure INSERT_DATA_TO_TEST_TABLE;23Procedure dropped.重新扫描这个表:


扫描完成后,这个问题已经修复。
但是,发现还是有感叹号,再次查看,发现还有一个视图 WRH$_SQLSTAT 有问题:

参考文档是需要重建 AWR 存储库:

重建 AWR 参考文档 How to Recreate the Automatic Workload Repository (AWR)? (Doc ID 782974.1):
1-- 查看 AWR 配置,记录一下2SQL> select snap_interval from wrm$_wr_control;34-- 禁用 AWR5SQL> execute dbms_workload_repository.modify_snapshot_settings(interval => 0);67-- 重启数据库到受限模式8SQL> shutdown immediate9SQL> startup restrict1011-- 执行 catnoawr 脚本删除 AWR,12.2 以上版本可能会遇到 ORA-600 [opiodr:] 报错12SQL> start $ORACLE_HOME/rdbms/admin/catnoawr.sql1314-- 检查是否所有 AWR 相关对象都被删除了15SQL> SELECT 'DROP TABLE ' || table_name || ' CASCADE CONSTRAINTS;'16FROM dba_tables where table_name like 'WRM$_%' or table_name like 'WRH$_%' or table_name like 'AWR%';1718-- 如果没有删除完成,可以手动执行删除19-- WRH$_SYSMETRIC_HISTORY_BL 在 19c 会被保留20SQL> drop table WRH$_SYSMETRIC_HISTORY_BL CASCADE CONSTRAINTS; 21drop type AWR_OBJECT_INFO_TABLE_TYPE;22drop type AWR_OBJECT_INFO_TYPE;23drop table WRH$_PLAN_OPERATION_NAME;24drop table WRH$_PLAN_OPTION_NAME;25drop table WRH$_MV_PARAMETER;26drop table WRH$_MV_PARAMETER_BL;27drop table WRH$_DYN_REMASTER_STATS;28drop table WRH$_PERSISTENT_QMN_CACHE;29drop table WRH$_DISPATCHER;30drop table WRH$_SHARED_SERVER_SUMMARY;31drop table WRM$_WR_USAGE;32drop table WRM$_SNAPSHOT_DETAILS;3334-- 重建 AWR35SQL> PURGE RECYCLEBIN;36SQL> start $ORACLE_HOME/rdbms/admin/catawrtb.sql37SQL> start $ORACLE_HOME/rdbms/admin/execsvrm.sql38SQL> start $ORACLE_HOME/rdbms/admin/utlrp.sql3940-- 重启数据库41SQL> shutdown immediate42SQL> startup4344-- 恢复 AWR 配置45SQL> execute dbms_workload_repository.modify_snapshot_settings(interval => 60);4647-- 手动创建快照48SQL> exec dbms_workload_repository.create_snapshot;4950-- 手动创建 SYS.WRMS$_SNAPSHOT 表51CREATE TABLE "SYS"."WRMS$_SNAPSHOT"52( "SNAP_ID" NUMBER NOT NULL ENABLE,53"DBID" NUMBER NOT NULL ENABLE,54"INSTANCE_NUMBER" NUMBER NOT NULL ENABLE,55"STARTUP_TIME" TIMESTAMP (3) NOT NULL ENABLE,56"BEGIN_INTERVAL_TIME" TIMESTAMP (3) NOT NULL ENABLE,57"END_INTERVAL_TIME" TIMESTAMP (3) NOT NULL ENABLE,58"FLUSH_ELAPSED" INTERVAL DAY (5) TO SECOND (1),59"SNAP_LEVEL" NUMBER,60"STATUS" NUMBER,61"ERROR_COUNT" NUMBER,62"BL_MOVED" NUMBER,63"SNAP_FLAG" NUMBER,64"SNAP_TIMEZONE" INTERVAL DAY (0) TO SECOND (0),65"STAGE_INST_ID" NUMBER NOT NULL ENABLE,66"STAGE_ID" NUMBER NOT NULL ENABLE67);重建 AWR 完成之后,再次扫描后:

问题已经解决。
第三步需要解决正式转换前的一些问题:

第一个问题可以修改配置,这 2 个建议都改成 Yes:

修改完之后,再次 Retest 一下:

还有一个问题需要解决,这个是因为有表空间开启了 force logging:

我查了下是 SYSTEM 和 SYSAUX 表空间:
1SQL> select tablespace_name,force_logging from dba_tablespaces;23TABLESPACE_NAME FOR4------------------------------ ---5SYSTEM YES6SYSAUX YES7UNDOTBS1 NO8TEMP NO9USERS NO手动修改为 NO:
1SQL> alter tablespace SYSTEM no force logging;23Tablespace altered.45SQL> alter tablespace SYSAUX no force logging;67Tablespace altered.📢 注意:字符集转换完成后需要修改回来。
再次 Retest 之后,已经没有报错:

可以正式开始转换数据库字符集。
右键选择转换字符集:

确认没问题,执行转换:

这里需要注意的是,在转换时最好确保没有用户连接数据库,否则报错:

转换前确认:


正式开始转换:

很快转换完成:

完成后建议重启一下数据库,因为我发现监听显示数据库是受限模式:
1[oracle@orcl19c:/home/oracle]$ lsnrctl stat23LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 21-FEB-2025 13:13:4545Copyright (c) 1991, 2019, Oracle. All rights reserved.67Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=orcl19c)(PORT=1521)))8STATUS of the LISTENER9------------------------10Alias LISTENER11Version TNSLSNR for Linux: Version 19.0.0.0.0 - Production12Start Date 21-FEB-2025 13:13:3213Uptime 0 days 0 hr. 0 min. 13 sec14Trace Level off15Security ON: Local OS Authentication16SNMP OFF17Listener Parameter File /u01/app/oracle/product/19.3.0/db/network/admin/listener.ora18Listener Log File /u01/app/oracle/diag/tnslsnr/orcl19c/listener/alert/log.xml19Listening Endpoints Summary...20 (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=orcl19c)(PORT=1521)))21 (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))22Services Summary...23Service "lucifer" has 1 instance(s).24 Instance "lucifer", status RESTRICTED, has 1 handler(s) for this service...25Service "luciferXDB" has 1 instance(s).26 Instance "lucifer", status RESTRICTED, has 1 handler(s) for this service...27The command completed successfully重启数据库:
1SQL> shutdown immediate2SQL> startup查看数据库字符集:
1SQL> set line2222 pages10002col parameter for a303col value for a204select * from nls_database_parameters where parameter='NLS_CHARACTERSET';56PARAMETER VALUE7------------------------------ --------------------8NLS_CHARACTERSET AL32UTF8查看客户端字符集:
1[oracle@orcl19c:/home/oracle]$ echo $NLS_LANG2AMERICAN_AMERICA.ZHS16GBK查看测试数据:
1SQL> set line2222 pages1000 wrap off tab off2col char_data for a803col clob_data for a804col description for a805col mixed_content for a806select * from lucifer.test_conversion order by id;
📢 注意:这里有几个字符乱码是在转换前就是乱码的。
如果此时修改客户端字符集 AL32UTF8:
1export NLS_LANG=AMERICAN_AMERICA.AL32UTF8查询数据就会乱码:

如果重新插入测试数据,就不会乱码:

到此,数据库字符集就转换完成了。
记得要将过程中修改的还原回去:
1SQL> alter tablespace SYSTEM force logging;23Tablespace altered.45SQL> alter tablespace SYSAUX force logging;67Tablespace altered.到这就结束啦。
由于之前没使用过 DMU 这个工具,所以本文也仅是作为测试记录所用,如有问题,欢迎在评论区指出!
本文部分内容参考自 Oracle MOS 文档内容:
