Oracle数据库迁移ZHS16GBK

前端之家收集整理的这篇文章主要介绍了Oracle数据库迁移ZHS16GBK前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

背景:两个数据库服务器,分别对应两个数据库,每个数据库对应一个实例,每个实例存在两个用户分别管理各自的数据,其中一个数据库采用ZHS16GBK编码,另一个数据库采用AL32UTF8编码,现将数据整合至一个采用AL32UTF8编码的数据库中完成数据的迁移。

数据库编码类型,避免错误

--sql--
SELECT * FROM V$NLS_PARAMETERS WHERE PARAMETER IN ('NLS_CHARACTERSET','NLS_NCHAR_CHARACTERSET');

完成编码确认以后就进行某度,提示各种方法尝试,例如修改字符编码,直接导库,设置编码后导库,结果都是有问题,而且问题还是不小,着实被坑了一把。所以能放弃某度就放弃他吧,目前最直观的结果就是带给你效率跟不上。

直接修改编码,失败,不过也提供代码参考,可以解决部分非中文字符问题,惨案如下:

--sql--
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;
--进行字符编码的切换,理论切换成功了会自动进行编码转换,但是会提示非超集问题,瞬间尴尬了,都不知道ZHS16GBK和AL32UTF8到底谁是谁的超集
--ALTER DATABASE CHARACTER SET AL32UTF8;
--由于上述的操作失败,直接设置字符集编码,该方法能够修改字符集,但是相应的内容并未真的进行编码转换,甚至导致乱码和数据查询失败,所以还是不起作用
ALTER DATABASE CHARACTER SET INTERNAL_USE AL32UTF8;
SHUTDOWN IMMEDIATE;
STARTUP;

修改编码后导库

1、这里涉及到多用户问题,单用户分别导出,然后导入到新的库会提示DBMS_JOB之类的警示信息,所以需要将多用户数据同时导出到一个dmp文件中,这样才能避免这个问题;

2、但是由于这种方法的设置编码后执行,依然无法解决跨编码导库问题,提示对应的字符长度不匹配,因此仍然失败。

惨案如下:

::bat
set NLS_LANG=SIMPLIFIED CHINESE_CHINA.AL32UTF8
::导出用户user1,user2的所有相关表至db.dmp文件中,操作日志为db.log
exp user/pwd@db log=db.log file=db.dmp owner=user1,user2

上述的方法执行了很多遍,然后问题无法解决,主要数据库数据量还是有一点的中间耗时比较多,最后找到部分新的解决思路,将数据库所有的varchar2的字段的长度调整1.5倍,链接如下:

http://blog.itpub.net/28602568/viewspace-1261407/

https://www.cnblogs.com/huangen88/p/4664759.html

上述两者非常明确,也提供了很好的思路,但是由于其sql语句不懂这么执行,主要是个人数据库水平有限,操作不成功所以只能重写自己调整

--sql--
SELECT
'ALTER TABLE ' || OWNER || '.' || TABLE_NAME || ' MODIFY( ' || COLUMN_NAME || ' VARCHAR2 (' || 
  (case when DATA_LENGTH * 1.5 > 4000 then '4000' else to_char(Ceil(DATA_LENGTH *1.5)) end)
   || '));'
  FROM DBA_TAB_COLUMNS UTC
 WHERE UTC.OWNER = UPPER('user')
   AND UTC.DATA_TYPE = 'VARCHAR2'
   AND UTC.TABLE_NAME NOT IN
       (SELECT TABLE_NAME
          FROM DBA_EXTERNAL_TABLES E
         WHERE E.OWNER = UPPER('user')) --筛选掉临时表
   AND UTC.TABLE_NAME NOT LIKE 'BIN%';
 --直接用自己的用户名替换到user
 --1、执行上上述sql语句
 --2、将执行的结果拷贝值新的sql,然后批量执行,忽略视图错误,这样就将所有varchar2的字段长度调整成功

这样就可以进行顺利的执行转换操作了,以下是相对完整的sql与bat:

关于多用户文件操作,直接在对应文件添加相应的sql语句即可,由于部分语法的差异,需要自行检查语句对应的结束符;注释-- /**/等等,这样的细节会导致意想不到的情况出现。

--sql--
--方案一匹配exp/imp

--链接数据库
--conn user/pwd@dbinstance as sysdba;
--删除用户用户数据,如果允许的话就删除,如果不允许只能在exp或imp语句中增加参数控制
drop user user cascade;
--重新创建用户,避免使用exp自动生成分配的账号用户,因为会导致其他问题,比如说用户被锁定
CREATE USER user IDENTIFIED BY "pwd"
/
--赋予DBA权限,根据设置的用户情况自行定义
GRANT DBA TO user
/
commit;
--如果有需要可以删除表空间和表空间文件,避免通过操作系统的方式直接删除表空间文件,否者会引起其他问题,例如数据库无法打开
drop tablespace tb_name including contents and datafiles;
--如果表空间被删除或表空间不存在则需要创建表空间,
--1、需要设置初始size大一些,避免表空间不足导致的异常;
--2、设置autoextend自动表空间增长,避免数据量大时导致的表空间膨胀不足;
--3、next,设置每次的扩张阈值尽量设置大写,如果过小也会导致导入数据产生异常
--4、maxsize,根据实际情况调整,如果不涉及所谓性能问题直接设置为无限制,这样避免数据膨胀导致的扩容异常
create tablespace tb_name
  logging   
  datafile 'C:\Program Files\Oracle\tablespace\tb_name.dbf'     
  size 1024m 
  autoextend on
  NEXT 200M MAXSIZE UNLIMITED
  extent management local;   
--退出sql语句
exit;

方案二,要求在对应服务器机器与客户机执行,禁止远程操作

--sql--
--方案二匹配expdp/impdp
--链接数据库
--conn user/pwd@dbinstance as sysdba;
--删除用户用户数据,如果允许的话就删除,如果不允许只能在exp或imp语句中增加参数控制
drop user user cascade;
--重新创建用户,避免使用exp自动生成分配的账号用户,因为会导致其他问题,比如说用户被锁定
CREATE USER user IDENTIFIED BY "pwd"
/
--赋予DBA权限,根据设置的用户情况自行定义
GRANT DBA TO user
/
commit;
--创建数据库路径,必须设置或使用之前已经存在的路径
--查询已经存在的路径
--select * from dba_directories;
create directory dpdata as 'C:\Program Files\Oracle\tablespace';
--给对应的数据库路径设置权限
grant read,write on directory dpdata to user
/
GRANT CONNECT TO user WITH ADMIN OPTION
/
GRANT RESOURCE TO user
/
-- 需要在数据导入端单独执行
--grant imp_full_database to user with admin option
/
--由于expdp要求在服务端执行,不支持远程操作,故需要在导出端单独执行该语句
--grant exp_full_database to user with admin option
/
commit;

--如果有需要可以删除表空间和表空间文件,避免通过操作系统的方式直接删除表空间文件,否者会引起其他问题,例如数据库无法打开
drop tablespace tb_name including contents and datafiles;
--如果表空间被删除或表空间不存在则需要创建表空间,
--1、需要设置初始size大一些,避免表空间不足导致的异常;
--2、设置autoextend自动表空间增长,避免数据量大时导致的表空间膨胀不足;
--3、next,设置每次的扩张阈值尽量设置大写,如果过小也会导致导入数据产生异常
--4、maxsize,根据实际情况调整,如果不涉及所谓性能问题直接设置为无限制,这样避免数据膨胀导致的扩容异常
create tablespace tb_name
  logging   
  datafile 'C:\Program Files\Oracle\tablespace\tb_name.dbf'     
  size 1024m 
  autoextend on
  NEXT 200M MAXSIZE UNLIMITED
  extent management local;   
--退出sql语句
exit;

以下关于执行的脚本

::bat
::方案一,匹配exp/imp在exp imp语句结束禁止加任何结束符
@echo off
::首选确认有没有设置%ORACLE_HOME%环境变量,然后确认是否在path环境变量中追加%ORACLE_HOME%/bin
::start /max ""  "%ORACLE_HOME%/bin"
::设置当前目录为导出导入的工作路径
set cur_dir=%cd%
:exp
::导出库
exp user/user@dbinstance log=%cur_dir%\db.log file=%cur_dir%\db.dmp owner=user1,user2
::导出完成后打开相应的目录自行找到对应的log检查是否执行正确
start /max ""  "%cur_dir%"
:imp
:: 确认表空间文件是否存在,如果不存在则创建,完成后打开对应表空间目录
set tablespace_path="C:\Program Files\Oracle\tablespace"
md %tablespace_path%
start /max ""  "%tablespace_path%"
sqlplus orcl/orcl@orcl as sysdba @%cur_dir%/create_user.sql

imp user/pwd log=%cur_dir%\impdb.log file=.%cur_dir%\db.dmp ignore=y fromuser=user_1 touser1 buffer=819200
imp user/pwd log=%cur_dir%\impdb.log file=%cur_dir%\db.dmp ignore=y fromuser=user_2 touser=user2 buffer=819200
::pause

方案二bat

::bat
::方案二,匹配expdp/impdp在expdp impdp语句结束禁止加任何结束符
@echo off
::首选确认有没有设置%ORACLE_HOME%环境变量,然后确认是否在path环境变量中追加%ORACLE_HOME%/bin
::start /max ""  "%ORACLE_HOME%/bin"
:pre
set cur_dir=%cd%
:: 确认表空间文件是否存在,如果不存在则创建,完成后打开对应表空间目录
set tablespace_path="C:\Program Files\Oracle\tablespace"
md %tablespace_path%
start /max ""  "%tablespace_path%"
::执行sql语句完成对应用户表空间表路径等创建
sqlplus user/pwd@dbinstance as sysdba @%cur_dir%/expdp_sql.sql
:exp
::需要在服务端导出库,不支持远程操作
expdp user/pwd@dbinstance schemas=user1,user2 dumpfile=expdp_db.dmp  logfile=expdp_db.log DIRECTORY=dpdata content=all
:imp
impdp user/pwd DIRECTORY=dpdata logfile=impdb_db.log dumpfile=expdp_db.dmp REMAP_SCHEMA=userfrom:userto
::pause

如此操作即可完成全部的导入导出操作,期间还会出现DBMS_JOB等异常,可以忽略,也可以自行找办法解决,后续根据实际情况进一步调整,如果导入导出过程中出现了异常情况,修改设置exp对应参数设置具体可以参考官方的文档

猜你在找的Oracle相关文章