1.說明
Oracle數據庫導入csv文件,
當csv文件較小時,
可以使用數據庫管理工具,
比如DBevaer導入到數據庫,
當csv文件很大時,
可以使用Oracle提供的sqlldr命令行工具,
能夠快速導入大量數據。
在數據庫之間進行數據遷移時,
特別是不同類型的數據庫,
使用csv文件是一種很好的選擇。
2.sqlldr用法
下面介紹sqlldr用法,
有一個USER_INFO.csv文件,
需要導入到數據庫中USER_INFO表,
而且有1.5億條數據,
要求導入耗時盡量小。
這里先介紹基本的導入方式,
然后介紹direct導入方式,
最后介紹parallel導入方式。
3.獲取csv文件
USER_INFO.csv文件內容如下,
這里僅選取了三條測試數據:
MSISDN,PROVINCE_CODE,CREATE_TIME
8617512570551,30,2019-10-31 17:16:09
8613063310680,33,2019-10-31 17:16:12
8613295281345,80,2019-10-31 17:16:14
4.創建USER_INFO表
CREATE TABLE "USER_INFO" (
"MSISDN" VARCHAR2(16),
"PROVINCE_CODE" VARCHAR2(4),
"CREATE_TIME" DATE,
CONSTRAINT "PK_USER_INFO_MSISDN" PRIMARY KEY ("MSISDN")
) TABLESPACE "USERS";
COMMENT ON COLUMN "USER_INFO"."MSISDN" IS '用戶手機號';
COMMENT ON COLUMN "USER_INFO"."PROVINCE_CODE" IS '省份編碼';
COMMENT ON COLUMN "USER_INFO"."CREATE_TIME" IS '用戶創建時間';
注意表中字段要和csv文件對應。
5.創建ctl文件
創建名為loaddata_USER_INFO.ctl的控制文件:
options(skip=1,BINDSIZE=20971520, ROWS=10000, READSIZE=20971520, ERRORS=999999999)
load data
infile '/home/oracle/USER_INFO.csv'
insert into table "USER_INFO"
fields terminated by ','
Optionally enclosed by '\''
(MSISDN,PROVINCE_CODE,CREATE_TIME "to_date(:CREATE_TIME, 'yyyy-mm-dd hh24:mi:ss')")
第1行是導入參數配置,
已經是支持大量數據導入的參數方案。
第3行infile指定導入的文件是USER_INFO.csv;
第4行into table前面的insert表示導入方式:
- insert :默認方式,在導入記錄前要求表為空;
- append :在表中追加新導入的記錄;
- replace :刪除舊記錄(等價delete from table語句),替換成新導入的記錄;
- truncate:刪除舊記錄(等價truncate table語句),替換成新導入的記錄;
into table后面指定導入數據庫表USER_INFO,
且表名必須大寫;
第5行指定每一行的字段是以逗號(,)分隔;
第6行指定字段是用兩個分號(')包圍起來的,可選的;
最后一行對應導入的字段,
注意如果導入的是時間字段,
需要指明時間轉換的格式。
6.使用sqlldr導入
指定需要導入的數據庫,
以及使用的control文件:
sqlldr userid=yuwen/ai123456@10.21.13.14:1521/orcl control=loaddata_USER_INFO.ctl
導入成功輸出日志如下:
SQL*Loader: Release 12.1.0.2.0 - Production on Thu Oct 31 17:37:49 2019
Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.
Path used: Conventional
Commit point reached - logical record count 3
Table "USER_INFO":
3 Rows successfully loaded.
Check the log file:
loaddata_USER_INFO.log
for more information about the load.
看到3條數據成功導入USER_INFO,
同時會生成loaddata_USER_INFO.log日志,
通過該日志可以查看更詳細的導入信息,
如果導入時發生錯誤,
可以查看到詳細的錯誤信息,
而且還會生成USER_INFO.bad文件,
bad文件原樣輸出了導入失敗的數據。
默認情況下ERRORS達到50個就會停止導入,
如果需要忽略錯誤繼續導入,
可以配置ERRORS最大值為999999999。
7.direct直接路徑方式
sqlldr支持direct參數,
使用直接路徑方式導效率非常高,
direct參數默認為FALSE,
上面第6步使用的就是默認常規路徑方式,
下面使用直接路徑方式,
進一步加快數據導入速度。
但是使用直接路徑方式會導致表的唯一索引(或主鍵)失效,
可以在導入前先刪除表的唯一索引,
然后在導入完成后重建索引即可,
如果有重復的數據,
需要先去重才能重建索引成功,
經過測試即使需要重建索引,
使用直接路徑方式還是比常規路徑方式快。
8.創建ctl文件(直接路徑方式)
創建名為loaddata_USER_INFO_direct.ctl的控制文件:
options(skip=1,COLUMNARRAYROWS=20971520, ROWS=10000, READSIZE=20971520, ERRORS=999999999)
load data
infile '/home/oracle/USER_INFO.csv'
insert into table "USER_INFO"
fields terminated by ','
Optionally enclosed by '\''
(MSISDN,PROVINCE_CODE,CREATE_TIME "to_date(:CREATE_TIME, 'yyyy-mm-dd hh24:mi:ss')")
這個文件和第5步中的區別在於,
options中的BINDSIZE換成了COLUMNARRAYROWS,
因為BINDSIZE是常規路徑綁定數組的大小,
而COLUMNARRAYROWS是直接路徑列數組的行數。
9.刪除主鍵
導入前需要先刪除USER_INFO表的主鍵:
ALTER TABLE USER_INFO DROP CONSTRAINT PK_USER_INFO_MSISDN;
10.使用sqlldr導入(直接路徑方式)
基本與第6步的命令相同,增加direct=true:
sqlldr userid=yuwen/ai123456@10.21.13.14:1521/orcl control=loaddata_USER_INFO_direct.ctl direct=true
數據成功導入日志如下:
SQL*Loader: Release 12.1.0.2.0 - Production on Fri Nov 1 10:48:10 2019
Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.
Path used: Direct
Load completed - logical record count 3.
Table "USER_INFO":
3 Rows successfully loaded.
Check the log file:
loaddata_USER_INFO_direct.log
for more information about the load.
11.重建主鍵
ALTER TABLE USER_INFO ADD CONSTRAINT PK_USER_INFO_MSISDN PRIMARY KEY(MSISDN);
至此使用直接路徑方式導入數據成功,
經過測試1.5億條不重復數據direct方式導入,
花費4分02秒,
然后重建主鍵花費19分14秒,
總耗時23分16秒。
然而使用常規路徑方式導入需要48個小時,
導入效率得到了極大的提升。
12.parallel並行導入
前面使用的是串行方式導入數據,
通過設置parallel為true可以並行導入,
在多核服務器上面能進一步提升導入效率。
需要注意並行方式僅僅在直接路徑方式時有效。
13.創建ctl文件(並行方式)
創建名為loaddata_USER_INFO_direct_parallel.ctl的控制文件:
options(skip=1,COLUMNARRAYROWS=20971520, ROWS=10000, READSIZE=20971520, ERRORS=999999999)
load data
infile '/home/oracle/USER_INFO.csv'
append into table "USER_INFO"
fields terminated by ','
Optionally enclosed by '\''
(MSISDN,PROVINCE_CODE,CREATE_TIME "to_date(:CREATE_TIME, 'yyyy-mm-dd hh24:mi:ss')")
這個文件和第8步中的區別在於,
並行方式只支持append導入,
而且要注意USER_INFO表不能有索引,
如果有需要先刪除。
14.使用sqlldr導入(並行方式)
基本與第10步的命令相同,增加parallel=true:
sqlldr userid=yuwen/ai123456@10.21.13.14:1521/orcl control=loaddata_USER_INFO_direct_parallel.ctl direct=true parallel=true
數據成功導入日志如下:
SQL*Loader: Release 12.1.0.2.0 - Production on Fri Nov 1 11:08:51 2019
Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.
Path used: Direct
SQL*Loader-281: Warning: ROWS parameter ignored in parallel mode.
Load completed - logical record count 3.
Table "USER_INFO":
3 Rows successfully loaded.
Check the log file:
loaddata_USER_INFO_direct_parallel.log
for more information about the load.
15.sqlldr命令說明
15.1.用法
SQLLDR keyword=value [,keyword=value,...]
15.2.參數說明
參數 | 說明 |
---|---|
userid | ORACLE 用戶名/口令 |
control | 控制文件名 |
log | 日志文件名 |
bad | 錯誤文件名 |
data | 數據文件名 |
discard | 廢棄文件名 |
discardmax | 允許廢棄的文件的數目 (全部默認) |
skip | 要跳過的邏輯記錄的數目 (默認 0) |
load | 要加載的邏輯記錄的數目 (全部默認) |
errors | 允許的錯誤的數目 (默認 50) |
rows | 常規路徑綁定數組中或直接路徑保存數據間的行數,默認: 常規路徑 64, 所有直接路徑) |
bindsize | 常規路徑綁定數組的大小 (以字節計) (默認 256000) |
silent | 運行過程中隱藏消息 (標題,反饋,錯誤,廢棄,分區) |
direct | 使用直接路徑 (默認 FALSE) |
parfile | 參數文件: 包含參數說明的文件的名稱 |
parallel | 執行並行加載 (默認 FALSE) |
file | 要從以下對象中分配區的文件 |
skip_unusable_indexes | 不允許/允許使用無用的索引或索引分區 (默認 FALSE) |
skip_index_maintenance | 沒有維護索引, 將受到影響的索引標記為無用 (默認 FALSE) |
commit_discontinued | 提交加載中斷時已加載的行 (默認 FALSE) |
readsize | 讀取緩沖區的大小 (默認 1048576) |
external_table | 使用外部表進行加載; NOT_USED, GENERATE_ONLY, EXECUTE (默認 NOT_USED) |
columnarrayrows | 直接路徑列數組的行數 (默認 5000) |
streamsize | 直接路徑流緩沖區的大小 (以字節計) (默認 256000) |
multithreading | 在直接路徑中使用多線程 |
resumable | 啟用或禁用當前的可恢復會話 (默認 FALSE) |
resumable_name | 有助於標識可恢復語句的文本字符串 |
resumable_timeout | RESUMABLE 的等待時間 (以秒計) (默認 7200) |
date_cache | 日期轉換高速緩存的大小 (以條目計) (默認 1000) |
no_index_errors | 出現任何索引錯誤時中止加載 (默認 FALSE) |
15.3.注意事項
命令行參數可以由位置或關鍵字指定。
前者的例子是 'sqlldr scott/tiger foo';
后這的例子是 'sqlldr control=foo userid=scott/tiger'。
位置指定參數的時間必須早於,
但不可遲於由關鍵字指定的參數。
例如允許 'sqlldr scott/tiger control=foo logfile=log',
但是不允許 'sqlldr scott/tiger control=foo log',
即使參數 'log' 的位置正確。
15.4.重要參數
rows:
加載的行數,默認值:常規路徑:64,直接路徑:全部。
常規路徑導入時,指定綁定數組中的行數。直
接路徑導入時,指一次從數據文件只讀取的行數。
該參數同時受bindsize制約,
如果rows每行實際占用大小超出bindsize的最大可用值,
則rows自動降低到bindsize最大可用值。
bindsize:
默認值:256000,以字節為單位。
為綁定數組指定最大可用空間,
用來存儲一次讀取的rows的記錄,
該值不能太小,至少要能放入一條邏輯記錄,
不然有可能造成加載失敗,
但是設置一個超大值也沒有意義,
浪費空間而且起不到任何效果。
direct:
直接路徑,默認值是false。
直接路徑加載並不是通過insert語句的方式提交數據,
直接路徑的加載甚至不走db_buffer,
因為不會存在緩沖區爭用,
直接路徑加載直接向數據文件寫數據,
因此效率較高。
file:
指定寫入的表空間數據文件。
通常是並行加載時應該會用到該參數,
指定file文件后,
要加載的內容即只向指定的數據文件寫入數據,
通過這種方式某些情況下可以減小磁盤間的競爭。
skip_unusable_indexes:
是否跳過不可用的索引,默認為false。
如果設置為true。在加載數據的時候,
如果沒加載的表中索引為unusable,
則該索引數據不維護,數據加載完以后也不會改變索引的狀態。
在oracle中也有一個參數叫skip_unusable_indexes,
但是sqlldr中的這個參數優先級比oracle數據庫內部的這個參數優先級高。
如果sqlldr中未設置這個參數,則以oracle中的skip_unusable_indexes參數為准。
skip_index_maintenance:
是否跳過索引維護,默認值為false。
該參數僅在直接路徑加載時有效,
如果設置為true,則數據加載過程中並不會維護索引,
因此數據加載完后會導致索引無效。
readsize:
緩沖區大小,默認值1048576字節,最大不超過20M。
該參數設置的值僅當從數據文件中讀取數據時有效,
如果數據包含在控制文件中則為64K,並不可修改。
streamsize:
流緩沖區大小,默認值是256000字節。
指定直接路徑加載時流緩沖區大小。
multithreading:
是否啟用多線程。
默認值:多cpu系統默認為true,單cpu的系統默認則為false。
該參數僅僅在直接路徑加載時有效。
date_cache:
日期轉換緩存,默認值為1000條。
指定一個專門用於日志轉換的緩存區,
如果處理的日期在其中,則不需要轉換,
否則直接取出來使用。
16.執行結果詳細日志
給出loaddata_USER_INFO_direct_parallel.log日志內容,
可以看到導入使用的配置,耗時等詳細信息,
供給大家參考:
SQL*Loader: Release 12.1.0.2.0 - Production on Fri Nov 1 11:20:07 2019
Copyright (c) 1982, 2014, Oracle and/or its affiliates. All rights reserved.
Control File: loaddata_USER_INFO_direct_parallel.ctl
Data File: /home/oracle/USER_INFO.csv
Bad File: USER_INFO.bad
Discard File: none specified
(Allow all discards)
Number to load: ALL
Number to skip: 1
Errors allowed: 999999999
Continuation: none specified
Path used: Direct - with parallel option.
Table "USER_INFO", loaded from every logical record.
Insert option in effect for this table: APPEND
Column Name Position Len Term Encl Datatype
------------------------------ ---------- ----- ---- ---- ---------------------
MSISDN FIRST * , O(') CHARACTER
PROVINCE_CODE NEXT * , O(') CHARACTER
CREATE_TIME NEXT * , O(') CHARACTER
SQL string for column : "to_date(:CREATE_TIME, 'yyyy-mm-dd hh24:mi:ss')"
SQL*Loader-281: Warning: ROWS parameter ignored in parallel mode.
Table "USER_INFO":
3 Rows successfully loaded.
0 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.
Bind array size not used in direct path.
Column array rows : 10000
Stream buffer bytes: 256000
Read buffer bytes:20971520
Total logical records skipped: 1
Total logical records read: 3
Total logical records rejected: 0
Total logical records discarded: 0
Total stream buffers loaded by SQL*Loader main thread: 1
Total stream buffers loaded by SQL*Loader load thread: 0
Run began on Fri Nov 01 11:20:07 2019
Run ended on Fri Nov 01 11:20:13 2019
Elapsed time was: 00:00:05.60
CPU time was: 00:00:00.44
17.參考文章
將CSV文件數據導入Oracle數據庫
(sqlldr)將xx.csv文件導入oracle數據庫
sqlldr總結參數介紹
Loading data in direct mode and unique index ORA-26026