暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

Oracle 修改数据库字符集大法 - DMU 工具


大家好,这里是公众号 DBA 学习之路,分享一些学习国产数据库路上的知识和经验。


前言

上篇说到 甩锅篇:Oracle 数据库特殊字符 ™ 乱码问题,最后结论是客户端字符集设置有问题,但是开发不认,硬说建库时选错字符集了,要修改数据库字符集为 AL32UTF8,那会儿咋不说!

最后,拗不过还是要改,先测试环境测试一下修改过程吧,本次使用 DMU 工具修改数据库字符集为 AL32UTF8。

记得点击 "DBA学习之路设为星标

后台回复【进群】,申请加入数据库学习交流群

DataDocks 数据码头 💬

最近联合几个大佬开通了一个付费微信群,加群后会有很多会员福利(分享各类技术文档,干货资源,问题解答等等),更有特邀嘉宾会定期在群内直播,解读 AWR,快问快答等!有兴趣联系微:Lucifer-0622


DMU 工具

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 月发布。


MOS 下载: https://updates.oracle.com/download/36716892.html

此版本中的新功能亮点包括

  1. 使用数据泵转换方法提供了优化的转换性能,适用于迁移包含 CLOB 数据的大型数据集,并减少了迁移停机时间窗口的需求。
  2. 索引检查功能可以检测并报告因 Unicode 迁移导致的潜在索引键大小违规问题,便于提前分析和修复。
  3. 区块链和不可变表支持使得区块链和不可变表能够自动无缝地迁移到 Unicode,同时完全保持数据完整性。


DMU 配置

当数据库版本大于 11.2.0.3 版本,使用 DMU 只需要安装 SYS.DBMS_DUMA_INTERNAL
 包,该包需要使用 sys 用户运行 $?/rdbms/admin/prvtdumi.plb
 来创建:


SQL> conn as sysdba
Connected.
SQL> @?/rdbms/admin/prvtdumi.plb

Library created.


Package created.

No errors.

Package body created.

No errors.

如果数据库版本低于 11.2.0.3,使用 DMU 需要在服务器端提前安装补丁 9825461

对于 DMU 不支持的版本/平台,使用 Csscan & Csalter
 或者 Csscan & Export/import
 是转为 AL32UTF8 的唯一方法。


启动 DMU 工具

如果数据库版本大于 12.1.0.2,在安装数据库软件时,会默认自带安装 DMU 2.0 客户端(用户界面):

在 ORACLE_HOME 目录下可以找到 dmu 的安装目录:


[oracle@orcl19c:/home/oracle]$ ll $ORACLE_HOME/dmu
总用量 20
drwxr-xr-x.  2 oracle oinstall   37 4月  17 2019 configuration
drwxr-xr-x.  9 oracle oinstall  100 4月  17 2019 dmu
-rw-r--r--.  1 oracle oinstall  238 7月  13 2017 dmucls.sh
-rw-r--r--.  1 oracle oinstall   53 7月  19 2012 dmu.sh
drwxr-xr-x.  2 oracle oinstall   24 4月  17 2019 dropins
drwxr-xr-x.  2 oracle oinstall   60 4月  17 2019 equinox
drwxr-xr-x.  2 oracle oinstall 4096 4月  17 2019 external
drwxr-xr-x.  8 oracle oinstall   85 4月  17 2019 ide
drwxr-xr-x.  6 oracle oinstall   57 4月  17 2019 jdev
drwxr-xr-x.  2 oracle oinstall 4096 4月  17 2019 jlib
drwxr-xr-x. 10 oracle oinstall 4096 4月  17 2019 modules
drwxr-xr-x.  5 oracle oinstall   50 4月  17 2019 netbeans
drwxr-xr-x.  3 oracle oinstall   23 4月  17 2019 sleepycat

建议下载最新的 DMU 版本,解压替换默认 DMU:


[root@orcl19c:/soft]# chown oracle:oinstall soft/p36716892_2310_Generic.zip
[root@orcl19c:/soft]# su - oracle
[oracle@orcl19c:/home/oracle]$ cd /soft/
[oracle@orcl19c:/soft]$ unzip -qo p36716892_2310_Generic.zip -d $ORACLE_HOME
[oracle@orcl19c:/soft]$ cd $ORACLE_HOME/dmu
[oracle@orcl19c:/u01/app/oracle/product/19.3.0/db/dmu]$ sh dmu.sh

必须使用图形化界面打开 DMU 工具:

初始化界面如下:

到这就算启动成功了。


DMU 转换字符集


创建测试数据

为了测试数据完整,这里可以创建一个测试表,插入一些测试数据:


SQL> create user lucifer identifiedbyoracle;
SQL> grant dba to lucifer;

SQL> conn lucifer/oracle

SQL> CREATETABLE test_conversion (
    idNUMBER PRIMARY KEY,
    char_data VARCHAR2(4000),
    clob_data CLOB,
    description VARCHAR2(500),
    mixed_content VARCHAR2(4000)
);

SQL> INSERTINTO test_conversion (id, char_data, clob_data, description, mixed_content)
VALUES (1NULL'这是一个包含中文字符的CLOB字段''描述:包含中文字符的CLOB字段'NULL);

SQL> INSERTINTO test_conversion (id, char_data, clob_data, description, mixed_content)
VALUES (2'This is a CHAR field containing English characters.'NULL'Description: CHAR field with English characters'NULL);

SQL> INSERTINTO test_conversion (id, char_data, clob_data, description, mixed_content)
VALUES (3NULL'包含特殊字符的CLOB字段:$#@!&*()''Description: CLOB field with special characters'NULL);

SQL> INSERTINTO test_conversion (id, char_data, clob_data, description, mixed_content)
VALUES (4NULL'包含表情符号的CLOB字段:😊😂👍 ''Description: CLOB field with emojis'NULL);

SQL> INSERTINTO test_conversion (id, char_data, clob_data, description, mixed_content)
VALUES (5'混合内容的字符字段:Hello,世界!1234 @#$%'NULL'Description: Mixed content CHAR field''混合内容的CLOB字段:Hello,世界!1234 @#$%');

SQL> commit;

SQL> set line2222 pages1000 wrap off tab off
col char_data for a80
col clob_data for a80
col description for a80
col mixed_content for a80
select * from lucifer.test_conversion orderbyid;


📢 注意:这里有几个字符是 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)[1] 文档,检查 SYS.SOURCE$
 对象扫描问题:


SQL> set line2222 pages1000
col owner for a10
col object_name for a30
col object_type for a20
SELECT OWNER, OBJECT_NAME, OBJECT_TYPE FROM dba_objects WHERE OBJECT_ID IN
(SELECTUNIQUE obj# FROM sys.source$ WHERE rowid IN
(SELECT row_id FROM system.dum$exceptionsWHERE obj# =
select OBJECT_ID FROM dba_objects where OWNER='SYS'AND OBJECT_NAME ='SOURCE$')
andTYPE ='8'))
ORDERBY owner;

OWNER      OBJECT_NAME                    OBJECT_TYPE
---------- ------------------------------ --------------------
SYS        INSERT_DATA_TO_TEST_TABLE      PROCEDURE

对了,这个是我之前测试数据的时候创建的一个存储过程,不符合要求:

很简单,将这个存储过程删除或者移动到其他用户下即可:


SQL> drop procedure INSERT_DATA_TO_TEST_TABLE;

Procedure dropped.

重新扫描这个表:

扫描完成后,这个问题已经修复。

但是,发现还是有感叹号,再次查看,发现还有一个视图 WRH$_SQLSTAT
 有问题:

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

重建 AWR 参考文档 How to Recreate the Automatic Workload Repository (AWR)? (Doc ID 782974.1)[2]


-- 查看 AWR 配置,记录一下
SQL> select snap_interval from wrm$_wr_control;

-- 禁用 AWR
SQL> execute dbms_workload_repository.modify_snapshot_settings(interval => 0);

-- 重启数据库到受限模式
SQL> shutdown immediate
SQL> startup restrict

-- 执行 catnoawr 脚本删除 AWR,12.2 以上版本可能会遇到 ORA-600 [opiodr:] 报错
SQL> start $ORACLE_HOME/rdbms/admin/catnoawr.sql

-- 检查是否所有 AWR 相关对象都被删除了
SQLSELECT'DROP TABLE ' || table_name || ' CASCADE CONSTRAINTS;'
FROM dba_tables where table_name like'WRM$_%'or table_name like'WRH$_%'or table_name like'AWR%';

-- 如果没有删除完成,可以手动执行删除
-- WRH$_SYSMETRIC_HISTORY_BL 在 19c 会被保留
SQL> droptable WRH$_SYSMETRIC_HISTORY_BL CASCADECONSTRAINTS;
droptype AWR_OBJECT_INFO_TABLE_TYPE;
droptype AWR_OBJECT_INFO_TYPE;
droptable WRH$_PLAN_OPERATION_NAME;
droptable WRH$_PLAN_OPTION_NAME;
droptable WRH$_MV_PARAMETER;
droptable WRH$_MV_PARAMETER_BL;
droptable WRH$_DYN_REMASTER_STATS;
droptable WRH$_PERSISTENT_QMN_CACHE;
droptable WRH$_DISPATCHER;
droptable WRH$_SHARED_SERVER_SUMMARY;
droptable WRM$_WR_USAGE;
droptable WRM$_SNAPSHOT_DETAILS;

-- 重建 AWR
SQL> PURGE RECYCLEBIN;
SQL> start $ORACLE_HOME/rdbms/admin/catawrtb.sql
SQLstart $ORACLE_HOME/rdbms/admin/execsvrm.sql
SQLstart $ORACLE_HOME/rdbms/admin/utlrp.sql

-- 重启数据库
SQLshutdownimmediate
SQLstartup

-- 恢复 AWR 配置
SQLexecute dbms_workload_repository.modify_snapshot_settings(interval => 60);

-- 手动创建快照
SQL> exec dbms_workload_repository.create_snapshot;

-- 手动创建 SYS.WRMS$_SNAPSHOT 表
CREATETABLE"SYS"."WRMS$_SNAPSHOT"
"SNAP_ID"NUMBERNOTNULLENABLE,
"DBID"NUMBERNOTNULLENABLE,
"INSTANCE_NUMBER"NUMBERNOTNULLENABLE,
"STARTUP_TIME"TIMESTAMP (3NOTNULLENABLE,
"BEGIN_INTERVAL_TIME"TIMESTAMP (3NOTNULLENABLE,
"END_INTERVAL_TIME"TIMESTAMP (3NOTNULLENABLE,
"FLUSH_ELAPSED"INTERVALDAY (5TOSECOND (1),
"SNAP_LEVEL"NUMBER,
"STATUS"NUMBER,
"ERROR_COUNT"NUMBER,
"BL_MOVED"NUMBER,
"SNAP_FLAG"NUMBER,
"SNAP_TIMEZONE"INTERVALDAY (0TOSECOND (0),
"STAGE_INST_ID"NUMBERNOTNULLENABLE,
"STAGE_ID"NUMBERNOTNULLENABLE
);

重建 AWR 完成之后,再次扫描后:

问题已经解决。


解决转换问题

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

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

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

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

我查了下是 SYSTEM 和 SYSAUX 表空间:


SQL> select tablespace_name,force_logging from dba_tablespaces;

TABLESPACE_NAME                FOR
------------------------------ ---
SYSTEM                         YES
SYSAUX                         YES
UNDOTBS1                       NO
TEMP                           NO
USERS                          NO

手动修改为 NO:


SQL> alter tablespaceSYSTEMnoforcelogging;

Tablespace altered.

SQL> altertablespaceSYSAUXnoforcelogging;

Tablespace altered.


📢 注意:字符集转换完成后需要修改回来。

再次 Retest 之后,已经没有报错:

可以正式开始转换数据库字符集。


转换字符集

右键选择转换字符集:

确认没问题,执行转换:

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

转换前确认:

正式开始转换:

很快转换完成:

完成后建议重启一下数据库,因为我发现监听显示数据库是受限模式:


[oracle@orcl19c:/home/oracle]$ lsnrctl stat

LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 21-FEB-2025 13:13:45

Copyright (c) 1991, 2019, Oracle.  All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=orcl19c)(PORT=1521)))
STATUS of the LISTENER
------------------------
Alias                     LISTENER
Version                   TNSLSNR for Linux: Version 19.0.0.0.0 - Production
Start Date                21-FEB-2025 13:13:32
Uptime                    0 days 0 hr. 0 min. 13 sec
Trace Level               off
Security                  ON: Local OS Authentication
SNMP                      OFF
Listener Parameter File   u01/app/oracle/product/19.3.0/db/network/admin/listener.ora
Listener Log File         u01/app/oracle/diag/tnslsnr/orcl19c/listener/alert/log.xml
Listening Endpoints Summary...
  (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=orcl19c)(PORT=1521)))
  (DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=EXTPROC1521)))
Services Summary...
Service "lucifer" has 1 instance(s).
  Instance "lucifer", status RESTRICTED, has 1 handler(s) for this service...
Service "luciferXDB" has 1 instance(s).
  Instance "lucifer", status RESTRICTED, has 1 handler(s) for this service...
The command completed successfully

重启数据库:


SQL> shutdown immediate
SQL> startup

查看数据库字符集:


SQL> set line2222 pages1000
col parameter for a30
col value for a20
select * from nls_database_parameters where parameter='NLS_CHARACTERSET';

PARAMETER                      VALUE
------------------------------ --------------------
NLS_CHARACTERSET               AL32UTF8

查看客户端字符集:


[oracle@orcl19c:/home/oracle]$ echo $NLS_LANG
AMERICAN_AMERICA.ZHS16GBK

查看测试数据:


SQL> set line2222 pages1000 wrap off tab off
col char_data for a80
col clob_data for a80
col description for a80
col mixed_content for a80
select * from lucifer.test_conversion order by id;

📢 注意:这里有几个字符乱码是在转换前就是乱码的。

如果此时修改客户端字符集 AL32UTF8:


export NLS_LANG=AMERICAN_AMERICA.AL32UTF8

查询数据就会乱码:

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

到此,数据库字符集就转换完成了。


收尾工作

记得要将过程中修改的还原回去:


SQL> alter tablespace SYSTEM force logging;

Tablespace altered.

SQL> alter tablespace SYSAUX force logging;

Tablespace altered.

到这就结束啦。


写在最后

由于之前没使用过 DMU 这个工具,所以本文也仅是作为测试记录所用,如有问题,欢迎在评论区指出!


参考文档

本文部分内容参考自 Oracle MOS 文档内容:

  • Oracle Database Migration Assistant for Unicode[3]
  • Oracle Database Migration Assistant for Unicode 23.1 文档[4]
  • Patch 36716892 - DMU Client 23.1.0 下载[5]
  • The Database Migration Assistant for Unicode (DMU) Tool (Doc ID 1272374.1)[6]
  • 如何选择或更改数据库字符集 (NLS_CHARACTERSET) (Doc ID 1525394.1)[7]
参考资料
[1] 

Tips For and Known Issues With The Database Migration Assistant for Unicode (DMU) Tool version (Doc ID 2018250.1): https://support.oracle.com/epmos/faces/DocContentDisplay?id=2018250.1

[2] 

How to Recreate the Automatic Workload Repository (AWR)? (Doc ID 782974.1): https://support.oracle.com/epmos/faces/DocContentDisplay?id=782974.1

[3] 

Oracle Database Migration Assistant for Unicode: https://www.oracle.com/cn/database/technologies/appdev/oracle-database-migration-assistant.html

[4] 

Oracle Database Migration Assistant for Unicode 23.1 文档: https://docs.oracle.com/en/database/oracle/dmu/23.1/

[5] 

Patch 36716892 - DMU Client 23.1.0 下载: https://updates.oracle.com/download/36716892.html

[6] 

The Database Migration Assistant for Unicode (DMU) Tool (Doc ID 1272374.1): https://support.oracle.com/epmos/faces/DocContentDisplay?id=1272374.1

[7] 

如何选择或更改数据库字符集 (NLS_CHARACTERSET) (Doc ID 1525394.1): https://support.oracle.com/epmos/faces/DocContentDisplay?id=1525394.1

文章转载自青年数据库学习互助会,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论