💫《博主主页》:奈斯DB-CSDN博客
🔥《擅长领域》:擅长阿里云AnalyticDB for MySQL(分布式数据仓库)、Oracle、MySQL、Linux、prometheus监控;并对SQLserver、NoSQL(MongoDB)有了解
💖如果觉得文章对你有所帮助,欢迎点赞收藏加关注💖
最近公司某个项目组,因为业务扩展所以需要在数据库中存储越南语,当前这套Oracle实例由于当时在搭建时使用的是GBK字符集,所以存储越南语就会存在乱码,因为 ZHS16GBK字符集只对汉字、英文字符、数字,+-*/等进行了编码,没有对越南语进行编码所以存储越南语时就会有乱码 ;而AL32UTF8字符集,基本上对全世界的字符进行了编码存储,对于越南语而言支持所有带声调的越南文字符(ư, ơ, ế, ệ等)【AL32UTF8不仅仅可以存储越南语,还可以存储日文、韩文等等】 ,那么就需要将业务用户由ZHS16GBK字符集转成AL32UTF8。
小伙伴们都知道数据泵可以完成对全库、单个生产用户、生产表、某个表空间的迁移,这些都是难度比较小的操作,如果有一个场景因为业务扩展需要存储 日文、越南语 ,现在的Oracle字符集是ZHS16GBK,但是,需要将Oracle的字符集改成AL32UTF8去存储日文、越南语,那么又应该怎么办呢?
既然抛出了这个问题就要解决这个问题,我先给出答案——最安全的办法就是重建一个实例,然后修改char/varchar2数据类型的长度,最后通过expdp/impdp数据泵导入进去,当前数据库实例上有多个业务用户,好在只有这一个业务用户有迁移字符集的需求,那么本篇文章主要是通过数据泵完成对一个业务用户字符集的迁移,即使是全库用户都需要转换字符集也是一样的流程。那么带着这个问题,让我们开始今天的内容,通过expdp/impdp轻松完成某个生产用户从GBK到UTF8编码的迁移。
特别说明💥:本篇文章部分知识点均来源于 Oracle 公开可查的官方文档手册,并结合了我个人的理解和案例演示。如有冲突,请联系,会立即处理。转载请标明出处😄
官方文档对于字符集作用的介绍(Oracle 19c):
Choosing a Character Set
官方文档对于字符集迁移的介绍(Oracle 19c):
Character Set Migration
目录
源生产库(ZHS16GBK,实例liudbywcs,RAC环境)部分
目标库(AL32UTF8,实例baj,RAC环境)部分
验证数据部分
Oracle字符集的作用:
Oracle数据库中的字符集(Character Set)是数据库全球化支持(NLS)的核心组成部分,它的存在和设计源于计算机处理多语言文本的基本需求。以下是Oracle官方文档中阐述的字符集作用和存在原因:
字符编码映射
建立二进制数据与人类可读字符之间的对应关系
例如:在ZHS16GBK中
0xB0A1
对应"啊",在AL32UTF8中0xE5958A
对应同一个汉字数据存储规范
定义每个字符占用的存储空间(单字节/多字节)
例如:US7ASCII每个字符固定1字节,AL32UTF8中文常用字占3字节
排序与比较规则
决定
ORDER BY
、WHERE
条件比较等操作的排序规则不同字符集对相同字符的排序顺序可能不同
Oracle常用字符集:
1.US7ASCII - 基础ASCII字符集基本特性:
7位编码标准,共128个字符(0x00-0x7F)
不支持任何扩展字符
每个字符固定占用1字节存储空间
支持范围:
英文字母(A-Z, a-z)
数字(0-9)
基本标点符号和特殊字符(!@#$%^&*等)
控制字符(换行、回车等)
典型问题:
-- 尝试存储非ASCII字符会报错或显示为? INSERT INTO test VALUES ('中文'); -- 结果: ??
适用场景:
纯英文应用系统
遗留系统维护
需要最小存储开销的环境
2. ZHS16GBK - 简体中文字符集
编码结构:
扩展GB2312标准,支持21003个汉字
双字节编码(0x8140-0xFEFE)
兼容ASCII(0x00-0x7F单字节)
字符范围:
简体中文(GB 18030-2000基本集)
常见繁体字
中文标点符号(全角)
部分日文假名和特殊符号
存储示例:
"中国" -> 0xD6D0 0xB9FA (2个双字节编码) "ABC" -> 0x41 0x42 0x43 (单字节ASCII兼容)
局限性:
不支持越南语、泰语等东南亚文字
部分生僻字可能无法显示
3. JA16SJIS - 日文字符集
编码特点:
基于Shift-JIS编码标准
混合单字节(ASCII)和双字节编码
包含JIS X 0201和JIS X 0208字符集
字符组成:
全角假名(平假名、片假名)
日文汉字(常用约6000字)
半角假名和符号
英数字(半角/全角)
编码示例:
"日本語" -> 0x93FA 0x967B 0x8CEA (3个双字节编码) "ハンカク" -> 0xB1 0xB2 0xB3 0xB4 (半角假名)
注意事项:
与EUC-JP编码不兼容
某些特殊符号可能显示异常
4. KO16KSC5601 - 韩文字符集
标准规范:
基于KS C 5601-1987标准
完全双字节编码(0xA1A1-0xFEFE)
包含2350个韩文音节和4888个汉字
字符构成:
韩文字母(谚文)
常用汉字
特殊符号和图形字符
编码特性:
"한국" -> 0xC7D1 0xB1B9 (2个双字节) "大韓民國" -> 0xB4EB 0xC7D1 0xB9DD 0xB0FA (4个双字节)
使用限制:
不包含部分新造韩文字
汉字数量有限
5. AL32UTF8 - Unicode字符集
核心优势:
完整Unicode支持(最新版本)
可变长度编码(1-4字节/字符)
兼容所有语言字符
编码方式:
ASCII字符:1字节(0x00-0x7F)
欧洲文字:通常2字节(如é: 0xC3A9)
中文/日文/韩文:通常3字节(中: 0xE4B8AD)
特殊符号/罕见字:4字节
存储对比:
GBK中的"中国":4字节(D6D0 B9FA) UTF8中的"中国":6字节(E4B8AD E59BBD)
关键特性:
-- 多语言混合存储示例 INSERT INTO multilingual VALUES ('中文Chinese日本語한국語ViệtNam');
实施建议:
字段长度调整:VARCHAR2(100)可能需扩大
排序规则:使用NLS_SORT参数指定
性能考虑:索引大小可能增加
比较总结:
特性 US7ASCII ZHS16GBK JA16SJIS KO16KSC5601 AL32UTF8 编码范围 128字符 2.1万汉字 6千日文 7千韩文 全Unicode 存储效率 最高 高 中 高 可变 多语言支持 仅英文 中/英 日/英 韩/中/英 全球语言 字节/字符 1 1或2 1或2 2 1-4 推荐场景 纯英文 简体中文 日文系统 韩文系统 国际系统
迁移建议:从任何单语言字符集迁移到AL32UTF8时,需特别注意:
字段长度可能不足(UTF8通常需要更多空间)
应用程序可能需要调整字符处理逻辑
导出/导入时明确指定字符集转换
字符集存储数据相关参数:
SQL> show parameter NLS_LENGTH_SEMANTICS
NLS_LENGTH_SEMANTICS:用于指定长度语义,有两个值BYTE、CHAR。mysql的字符集转换不同于oracle,因为oracle是字节byte所以涉及到列长度的转换,但mysql是存储是用char,所以不涉及到列的转换。但是Oracle可以通过NLS_LENGTH_SEMANTICS参数设置用BYTE还是CHAR存储数据,默认是BYTE字节存储。这个参数主要是针对char和varchar2这两种数据类型,数据存储是使用字节byte还是字符char设计的。对于NCHAR、NVARCHAR2、CLOB和NCLOB列始终基于char字符。
- BYTE:以字节的形式存储数据,默认值。gbk迁移到utf8就会涉及到char和varchar2数据类型的长度转换。
- CHAR:以字符的形式存储数据,gbk迁移到utf8不会涉及到长度转换。
注意:Oracle强烈建议不要在运行的实例中将参数设置为CHAR,因为可能导致许多现有安装脚本或者表数据意外地创建具有字符长度语义的列,从而导致运行时错误,包括缓冲区溢出。可以考虑在新实例中修改,新实例修改参考下面的案例一,修改长度语义只对后续手动创建的表生效,现有表还是原byte
首先了解为什么迁移字符集需要修改char/varchar2数据类型的长度,而不需要修改数值、日期等数据类型的长度。下面我们先看案例——汉字和字符在char/varchar2/nchar/nvarchar2数据类型中的占用的字节:
-
char(n)存放定长的字符串,最大存放2000 bytes
AMERICAN_AMERICA.ZHS16GBK(一个字符1字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t1_gbk (name char(32)); ###创建字段为char32数据类型的liu_oracleoltp_ywcs_t1_gbk表,数据类型的字符串长度一般是16的倍数,例32,64,128等 SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t1_gbk values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t1_gbk values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t1_gbk; ###dump为展现这个行(name)的详细内容 ###插入数据的详细内容,数字代表字码,79代表字母O,空格用32代码表示
AMERICAN_AMERICA.AL32UTF8(一个字符1字节,一个汉字为3字节)
SQL> create table liu_oracleoltp_ywcs_t2_utf8 (name char(32)); ###创建字段为char32数据类型的liu_oracleoltp_ywcs_t2_utf8表,数据类型的字符串长度一般是16的倍数,例32,64,128等 SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t2_utf8 values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t2_utf8 values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t2_utf8; ###dump为展现这个行(name)的详细内容 ###插入数据的详细内容,数字代表字码,79代表字母O,空格用32代码表示
-
varchar2(n):存放可变长长度的字符集,最大可以存放4000 bytes
AMERICAN_AMERICA.ZHS16GBK(一个字符1字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t3_gbk (name varchar2(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t3_gbk(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t3_gbk(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t3_gbk; ###1、存放了‘Oracle’的6个字符,实际存放数据库中,就只占用了6个(‘Oracle’),其余的剩下的字符就被回收了。 ###2、如果插入数据是固定长度的,比如手机号码(11位)、身份证号(18位),则应当使用char来存放,这样的好处是查询与检索速度较快。原因为查询char类型的字段时,作为整体进行查询,而varchar2是一个个数据进行比对的。而如果存放的字符串的长度不固定,则建议使用varchar2(size)
AMERICAN_AMERICA.AL32UTF8(一个字符1字节,一个汉字为3字节)
SQL> create table liu_oracleoltp_ywcs_t4_utf8 (name varchar2(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t4_utf8(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t4_utf8(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t4_utf8; ###1、存放了‘Oracle’的6个字符,实际存放数据库中,就只占用了6个(‘Oracle’),其余的剩下的字符就被回收了。 ###2、如果插入数据是固定长度的,比如手机号码(11位)、身份证号(18位),则应当使用char来存放,这样的好处是查询与检索速度较快。原因为查询char类型的字段时,作为整体进行查询,而varchar2是一个个数据进行比对的。而如果存放的字符串的长度不固定,则建议使用varchar2(size)
-
nchar(n):根据字符集而定的固定长度字符集,nchar(n)最大存放2000 bytes
AMERICAN_AMERICA.ZHS16GBK(一个字符2字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t5_gbk (name nchar(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t5_gbk(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t5_gbk(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t5_gbk;
AMERICAN_AMERICA.AL32UTF8(一个字符2字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t7_utf8 (name nchar(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t7_utf8(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t7_utf8(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t7_utf8;
-
nvarchar2(n):根据字符集而定的固定长度字符集,nvarchar2(n)最大存放4000 bytes。
AMERICAN_AMERICA.ZHS16GBK(一个字符2字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t6_gbk (name nvarchar2(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t6_gbk(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t6_gbk(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t6_gbk;
AMERICAN_AMERICA.AL32UTF8(一个字符2字节,一个汉字为2字节)
SQL> create table liu_oracleoltp_ywcs_t8_utf8 (name nvarchar2(16)); SQL> show parameter NLS_LENGTH_SEMANTICS; ###首先确定存放字符的类型,默认是字节byte存储,有char、byte两个值。 SQL> insert into liu_oracleoltp_ywcs_t8_utf8(name) values('Oracle'); SQL> insert into liu_oracleoltp_ywcs_t8_utf8(name) values('甲骨文');SQL> select name,dump(name) from liu_oracleoltp_ywcs_t8_utf8;
那么现在明白了为什么修改字符集时需要增加 char/varchar2数据类型 长度了吧!对于NCHAR、NVARCHAR2、CLOB和NCLOB列始终基于char字符,CLOB和NCLOB大字段的数据类型一般是不会指定长度的,所以也就不会涉及到长度的增加了,所以这里我就不演示了。
那么总结一下:
Oracle字符集的修改不要在现有的实例上直接去修改,因为oracle默认是 字节byte 所以涉及到列长度的转换,转换涉及到 char和varchar2 两种数据类型,其他数据类型不涉及到转换,也有通过 在线修改单机或者rac的字符集 ,但是会有很大的风险,所以通过expdp/impdp数据泵是最有效的方案。
源生产库(ZHS16GBK,实例liudbywcs,RAC环境)部分
1、字符集存储数据参数
SQL> show parameter NLS_LENGTH_SEMANTICS;
###BYTE:以字节的形式存储数据,默认值。gbk迁移到utf8就会涉及到char和varchar2数据类型的长度转换。
2、创建数据泵的dmp文件存放目录
[root@rac1 ~]# mkdir /liu [root@rac1 ~]# chown oracle:oinstall /liu ###文件liu(路径/liu)在/dev/sdb3下挂载,将文件的所属用户和目录改为oracle:oinstall[root@rac1 ~]# sqlplus / as sysdba SYS@orcl> create directory BACKUP20200328 as '/liu'; SYS@orcl> grant all on directory BACKUP20200328 to system ; ###创建数据泵的转储路径(在使用expdp时,指定到liu目录时,数据文件就会生成在/liu路径下)。赋予给所有用户目录liu的所有执行权限,为了以后普通用户使用expdp时有权限将dmp数据文件导入到/liu下。
3、导出的数据库为ZHS16GBK,只导出生产baj这个用户
[oracle@rac1 ~]$ export ORACLE_SID=liudbywcs1
[oracle@rac1 ~]$ echo $ORACLE_SID[oracle@rac1 ~]$ expdp baj/baj directory=BACKUP20200328 dumpfile=expdp_liudbywcs_baj_%U.dmp logfile=expdp_orcl_baj.log schemas=baj parallel=4 cluster=n
4、生成生产库的业务表空间SQL语句:
ps:排查掉SYSAUX、SYSTEM、TEMP、UNDOTBS1、USERS这些系统表空间的创建
SQL> set linesize 500 set pagesize 99col file_name for a70 col file_id for 9999999 col status for a10 col ts_name for a25 col cur_mb for 99999 select status, file_id, file_name, tablespace_name ts_name,blocks/128 tolal_mb, maxblocks/128 max_mb,AUTOEXTENSIBLE,status,online_status from dba_data_files order by file_name;SQL> SET LONG 2000000 PAGESIZE 0 head off verify off feedback off linesize 180 SQL> select dbms_metadata.get_ddl('USER','BAJ') from dual; ###查看创建用户的语句,需要确定默认的表空间和默认的临时表空间
SQL> select dbms_metadata.get_ddl('TABLESPACE','NNC_DATA01') from dual; ###查看创建表空间的语句
SQL> select dbms_metadata.get_ddl('TABLESPACE','NNC_INDEX01') from dual;
目标库(AL32UTF8,实例baj,RAC环境)部分
1、生产baj用户导入前需要注意的事情:
1)关注归档目录,定时进行删除,避免空间耗尽。可以考虑先关闭归档
2)baj数据量有500G以上,导入过程中undo和temp占用很多,适当扩容。
博主在实际迁移过程中Undo表空间给7个,总大小210G,并且减少undo_retention为300秒
Temp表空间给3个,总大小90G
3)数据文件看情况增加
2、在服务器上创建一个AL32UTF8字符集的实例baj
这里就不演示安装实例过程中,需要主要的是字符集需要为AL32UTF8
3、确认字符集调整undo保留时间
[oracle@rac1 ~]# export ORACLE_SID=baj1
[oracle@rac1 ~]# echo $ORACLE_SIDSQL> alter system set undo_retention=300 scope=both sid='*'; --导入完成之后修改回来SQL> select * from nls_database_parameters;
SQL> select * from v$nls_parameters;
SQL> select userenv('language') from dual ;
4、创建表空间
SQL>
set linesize 500
set pagesize 99
col file_name for a70
col file_id for 9999999
col status for a10
col ts_name for a25
col cur_mb for 99999
select status, file_id, file_name, tablespace_name ts_name,blocks/128 tolal_mb, maxblocks/128 max_mb,AUTOEXTENSIBLE,status,online_status from dba_data_files order by file_name;alter tablespace UNDOTBS1 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS1 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS1 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS1 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS1 add datafile '+DATADG' size 31G autoextend on;alter tablespace UNDOTBS2 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS2 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS2 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS2 add datafile '+DATADG' size 31G autoextend on;
alter tablespace UNDOTBS2 add datafile '+DATADG' size 31G autoextend on;alter tablespace temp add tempfile '+DATADG' size 31G autoextend on;
alter tablespace temp add tempfile '+DATADG' size 31G autoextend on; CREATE TABLESPACE "NNC_DATA01" DATAFILE
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 5G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend onLOGGING ONLINE PERMANENT BLOCKSIZE 8192EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULTNOCOMPRESS SEGMENT SPACE MANAGEMENT AUTO;
CREATE TABLESPACE "NNC_INDEX01" DATAFILE
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend onLOGGING ONLINE PERMANENT BLOCKSIZE 8192EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULTNOCOMPRESS SEGMENT SPACE MANAGEMENT AUTO;CREATE TABLESPACE "NNC_INDEX01" DATAFILE
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend on,
'+DATADG' SIZE 1G autoextend onLOGGING ONLINE PERMANENT BLOCKSIZE 8192EXTENT MANAGEMENT LOCAL AUTOALLOCATE DEFAULTNOCOMPRESS SEGMENT SPACE MANAGEMENT AUTO;
5、创建存放DMP文件夹的引用地址
SQL> create directory baj_dir as '/home/oracle/backup20200328';
SQL> grant all on directory baj_dir to system;
6、linux下使用impdp工具导入(只是导入对象):
[oracle@rac1 ~]# export ORACLE_SID=baj1
[oracle@rac1 ~]# echo $ORACLE_SID[oracle@rac1 ~]# impdp system/oracle directory=baj_dir dumpfile=expdp_orcl_baj_01.dmp,expdp_orcl_baj_02.dmp,expdp_orcl_baj_03.dmp,expdp_orcl_baj_04.dmp logfile=impdp_baj_baj_metadata_only.log schemas=baj parallel=8 CONTENT=metadata_only table_exists_action=append cluster=n
####impdp导入之前,需要在目标数据库上创建相应表空间对象即可;而对于imp导入时需要在目标数据库上创建相应的用户、权限、表空间等对象。
7、旧库迁移到新库,旧库编码是GBK,新库是UTF-8,一个汉字GBK占2个字节,UTF-8占三个字节,故对varchar2和char类型字段扩容二分之一
注意:有些业务表是定长char数据类型,但是内容只有字符,没有汉字,如果统一进行扩容的话可能会影响程序对char数据类型的判断,所以对于char数据类型按照要求扩长或者不扩长,哪些char必须要扩容只有在导入的时候报错了再考虑对char进行扩容。
[oracle@rac1 ~]# sqlplus baj/123456 ###连接到baj用户执行下面操作
扩展char小于1300的SQL语句:
SQL> set pagesize 0; SQL> spool /home/oracle/char1.sqlSELECT 'alter table ' || t_column.table_name || ' modify ' ||t_column.column_name || ' char(' || (t_column.data_length + ceil(t_column.data_length * 0.5)) || ');' AS alter_sqlstrFROM user_tab_columns t_column, user_tables t_tablesWHERE t_column.table_name = t_tables.table_nameAND t_column.data_length <= 1300AND t_column.data_type = 'CHAR'; SQL> spool off
扩展char大于1300且小于2000的SQL语句:
SQL> set pagesize 0; SQL> spool /home/oracle/char2.sqlSELECT 'alter table ' || t_column.table_name || ' modify ' ||t_column.column_name || ' char(2000);' AS alter_sqlstrFROM user_tab_columns t_column, user_tables t_tablesWHERE t_column.table_name = t_tables.table_nameAND t_column.data_length > 1300AND t_column.data_length < 2000AND t_column.data_type = 'CHAR'; SQL> spool off
扩展varchar2大于2600且小于4000的SQL语句:
SQL> set pagesize 0; SQL> spool /home/oracle/char3.sqlSELECT 'alter table ' || t_column.table_name || ' modify ' ||t_column.column_name || ' varchar2(4000);' AS alter_sqlstrFROM user_tab_columns t_column, user_tables t_tablesWHERE t_column.table_name = t_tables.table_nameAND t_column.data_length > 2600AND t_column.data_length < 4000AND t_column.data_type = 'VARCHAR2'; SQL> spool off
扩展varchar2小于2600的SQL语句:
SQL> set pagesize 0; SQL> spool /home/oracle/char4.sqlSELECT 'alter table ' || t_column.table_name || ' modify ' ||t_column.column_name || ' varchar2(' || (t_column.data_length + ceil(t_column.data_length * 0.5)) || ');' AS alter_sqlstrFROM user_tab_columns t_column, user_tables t_tablesWHERE t_column.table_name = t_tables.table_nameAND t_column.data_length <= 2600AND t_column.data_type = 'VARCHAR2'; SQL> spool off
8、执行需要扩容的SQL文本:
[oracle@rac1 ~]# sqlplus baj/123456
###连接到baj用户执行下面操作SQL> /home/oracle/char1.sql
SQL> /home/oracle/char2.sql
SQL> /home/oracle/char3.sql
SQL> /home/oracle/char4.sql
###执行char1.sql、char2.sql、char3.sql、char4.sql之前,需要删除多余的spool和spool off内容只保留alter table内容
9、如果有些表扩长到varchar2(4000)也不足,所以需要修改为clob数据类型
ps:在第一次导入的时候发现导入WA_CLASSITEM表时,VFORMULASTR字段扩容到了varchar2(4000),但数据长度需要4070,varchar2最大长度为4000,所以只能通过alter table修改数据类型为clob才能解决,那么只能将生产用户删掉,然后再来一遍哦!
SQL> ALTER TABLE WA_CLASSITEM DROP COLUMN VFORMULASTR;
SQL> ALTER TABLE WA_CLASSITEM add VFORMULASTR CLOB;
10、linux下使用impdp工具导入(导入对象的数据):
[oracle@rac1 ~]# export ORACLE_SID=baj1
[oracle@rac1 ~]# echo $ORACLE_SID[oracle@rac1 ~]# impdp system/oracle directory=baj_dir dumpfile=expdp_orcl_baj_01.dmp,expdp_orcl_baj_02.dmp,expdp_orcl_baj_03.dmp,expdp_orcl_baj_04.dmp logfile=impdp_baj_baj_data_only.log schemas=baj parallel=8 CONTENT=data_only table_exists_action=append cluster=n
####impdp导入之前,需要在目标数据库上创建相应表空间对象即可;而对于imp导入时需要在目标数据库上创建相应的用户、权限、表空间等对象。
验证数据部分
第一步:验证数据大小
SQL> select sum(bytes) / 1024 / 1024 / 1024 || 'G' sumfrom dba_segmentswhere owner in ('BAJ')
第二步:验证有无失效的对象(目标数据库上执行)
SQL> select * from dba_objects where status!='VALID' and owner in('BAJ');
SQL> @?/rdbms/admin/utlrp.sql ---有无效对象的话,进行无效对象的编译(最大可能自动修复无效对象)。
第三步:收集统计信息(目标数据库上执行)
[oracle@rac1 ~]# vi status.sql begin
dbms_stats.gather_database_stats;
end;
/ [oracle@rac1 ~]# nohup sqlplus / as sysdba @status.sql & ---因为收集统计信息时间长,所以写个sh后台运行
第四步:查看哪些表的统计信息被锁定(stattype_locked字段为ALL的表示锁定了表的统计信息,默认stattype_locked字段为空表示可以收集统计信息):
SQL> select * from dba_ind_statistics where stattype_locked='ALL' AND OWNER='BAJ';
SQL> select * from dba_tab_statistics where stattype_locked='ALL' AND OWNER='BAJ';SQL> begindbms_stats.unlock_schema_stats(ownname => 'BAJ');end;/
第五步:验证对象(目标数据库上执行)
SQL> select object_type t_object_type, count(*) t_countfrom dba_objectswhere owner in('BAJ')group by object_type
###注:oracle的对象类型可以分的很详细,表、表分区、表子分区是不同的类型。
第六步:对比导入和导出日志
第七步:将undo时间修改回最佳值
SQL> alter system set undo_retention=10800 scope=both sid='*';
兄弟们终于写完了!!!这篇文章是我在下班后写了3个小时奋战到深夜23点才搞定的,之所以分享是因为大家之后肯定会用到的,所以别吝啬你的小手, 点赞、收藏、加关注 。给我来点动力呗。那么我们下一篇文章见——expdp/impdp高效完成全部生产用户的全库迁移。