將表 從mysql 遷移到oracle

myownstars發表於2010-12-16
昨天接到一個任務,將一個表從mysql遷移到oracle,表總共有300多萬條記錄。
解決思路;先將資料從mysql匯出一個文字檔案,然後傳送的目標伺服器,進而用sqlldr將其載入至oracle

第一步: 匯出檔案
Mysql  匯出檔案
在此省去表結構
mysql> select * from justin into outfile '/data/mysqldata/justin.txt' fields terminated by ',' enclosed by '"';

第二步
將其傳輸到目標伺服器
[rkun@localhost mysqldata]$ scp justin.txt oracle@192.168.0.1:
oracle@192.168.0.1's password:
justin.txt     

第三步
目標伺服器上建立control.ctl
load data
characterset UTF8
infile '/home/oracle/justin
new.txt'
append into table justin
fields terminated by ',' OPTIONALLY ENCLOSED BY '"'
(
"ID" sequence(MAX,1),
**********
**********
)
注:我們在此採用sqlldr直接路徑載入,必須在控制檔案指定載入字符集,使之與目標資料庫保持一致,否則會預設採用OS端的字符集,中文字元會產生亂碼
另外,mysql中id對應值全為0,而對應的oracle表該欄位為主鍵,為防止主鍵衝突,使用sqlldr的sequence功能生成主鍵,sequence(max,1)插入前找出表中id最大值並自動將當前值加1;
同時此功能要求在文字檔案中去掉對應的id列
該表總共有22列 使用cut命令 去除第一列
[oracle@justin ~]$ more justin.txt | cut -d ',' -f 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22 > justinnew2.txt

另外mysql匯出文字檔案的時候,當欄位為空值的時候,其對應的字元為\N, 當使用sqlldr載入至Oracle,會報錯
Record 2: Rejected - Error on table justin, column "justin11".
ORA-01722: invalid number

採用tr命令來消除,將\N用空格來代替
[oracle@justin ~]$ more justinnew2.txt | tr '\\N'  '  ' >  justinnew.txt

接下來呼叫sqlldr命令
[oracle@justin ~]$ $ORACLE_HOME/bin/./sqlldr userid=justin/****** control=control.ctl  readsize=500000 rows=2000   direct=true log=justin.log

採用sqlldr載入, 報錯如下
Record 5957: Rejected - Error on table justin, column "LOG_LEVEL".
Column not found before end of logical record (use TRAILING NULLCOLS)
日誌顯示從第5957行開始,找不到最後一列"LOG_LEVEL"的值了
檢視一下發現 經過os命令轉變後 原檔案的相應行的最後一列“-1”被切掉了
[oracle@justin ~]$ head -5960 justin.txt | tail -10
\N,\N,\N,\N,"1","0"
\N,\N,\N,\N,"1","0"
\N,\N,\N,\N,"1","0"
\N,\N,\N,\N,"1","0"
\N,\N,\N,\N,"1","0"
\N,\N,\N,\N,"1","0"
\N,\N,"805688",\N,"1","-1"\N,\N,"5579643",\N,"1","-1"
\N,\N,"6092314",\N,"1","-1"
\N,\N,"788776",\N,"1","-1"
[oracle@justin ~]$ head -5960 justinnew.txt | tail -10
  ,  ,  ,"1","0"
  ,  ,  ,"1","0"
  ,  ,  ,"1","0"
  ,  ,  ,"1","0"
  ,  ,  ,"1","0"
  ,  ,  ,"1","0"
  ,  ,"805688",  ,"1" —-只有了1,後面的”-1”沒有了
  ,  ,"5579643",  ,"1"
  ,  ,"6092314",  ,"1"
  ,  ,"788776",  ,"1"

經確認,問題出在cut命令上,我本意是想把第一列去掉,沒想到從5957行開始,把最後一列也給切了,導致報錯Column not found before end of logical record (use TRAILING NULLCOLS)
反覆驗證後發現了問題,當呼叫cut命令時候,採用','作為分隔符,但是中間有個欄位值裡面已經有了',',類似"asdgasg,asdf",故os把它當作了兩個不同的列來處理。
解決方法: 呼叫cut時候後面多加一個數字23即可
注: 我們的sqlldr的控制檔案也是採用','作為分隔符,但是由於加上了fields terminated by ',' OPTIONALLY ENCLOSED BY '"',故不會像cut命令一樣把此欄位當成兩個來處理


重新載入 發現又報錯 但是這次已經載入了50多萬行 比上次有進步了

先把能夠載入的全都載入進去 設定errors引數為10000
[oracle@justin ~]$ $ORACLE_HOME/bin/./sqlldr userid=justin/******* control=control.ctl  readsize=500000 rows=2000   direct=true log=justin.log errors=10000
結果顯示才95條遺漏的
Table justin
:
  3006277 Rows successfully loaded.
  95 Rows not loaded due to data errors.
  0 Rows not loaded because all WHEN clauses were failed.
  0 Rows not loaded because all fields were null.
考慮到是日誌跟蹤表 這個錯誤率還是可以接受的

[ 本帖最後由 myownstars 於 2011-2-25 17:51 編輯 ]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15480802/viewspace-688359/,如需轉載,請註明出處,否則將追究法律責任。

相關文章