Oracle數據庫遷移ZHS16GBK

背景:兩個數據庫服務器,分別對應兩個數據庫,每一個數據庫對應一個實例,每一個實例存在兩個用戶分別管理各自的數據,其中一個數據庫採用ZHS16GBK編碼,另外一個數據庫採用AL32UTF8編碼,現將數據整合至一個採用AL32UTF8編碼的數據庫中完成數據的遷移。html

數據庫編碼類型,避免錯誤sql

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

完成編碼確認之後就進行某度,提示各類方法嘗試,例如修改字符編碼,直接導庫,設置編碼後導庫,結果都是有問題,並且問題仍是不小,着實被坑了一把。因此能放棄某度就放棄他吧,目前最直觀的結果就是帶給你效率跟不上。數據庫

直接修改編碼,失敗,不過也提供代碼參考,能夠解決部分非中文字符問題,慘案以下:bash

--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;

修改編碼後導庫服務器

一、這裏涉及到多用戶問題,單用戶分別導出,而後導入到新的庫會提示DBMS_JOB之類的警示信息,因此須要將多用戶數據同時導出到一個dmp文件中,這樣才能避免這個問題;性能

二、可是因爲這種方法的設置編碼後執行,依然沒法解決跨編碼導庫問題,提示對應的字符長度不匹配,所以仍然失敗。編碼

慘案以下:spa

::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/.net

http://www.javashuo.com/article/p-ukusruso-dr.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
 --一、執行上上述sql語句
 --二、將執行的結果拷貝值新的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;
--若是表空間被刪除或表空間不存在則須要建立表空間,
--一、須要設置初始size大一些,避免表空間不足致使的異常;
--二、設置autoextend自動錶空間增加,避免數據量大時致使的表空間膨脹不足;
--三、next,設置每次的擴張閾值儘可能設置大寫,若是太小也會致使導入數據產生異常
--四、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;
--若是表空間被刪除或表空間不存在則須要建立表空間,
--一、須要設置初始size大一些,避免表空間不足致使的異常;
--二、設置autoextend自動錶空間增加,避免數據量大時致使的表空間膨脹不足;
--三、next,設置每次的擴張閾值儘可能設置大寫,若是太小也會致使導入數據產生異常
--四、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對應參數設置具體能夠參考官方的文檔

相關文章
相關標籤/搜索