背景:兩個數據庫服務器,分別對應兩個數據庫,每一個數據庫對應一個實例,每一個實例存在兩個用戶分別管理各自的數據,其中一個數據庫採用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對應參數設置具體能夠參考官方的文檔