Sql*Loader詳解

在 Oracle 數據庫中,咱們一般在不一樣數據庫的表間記錄進行復制或遷移時會用如下幾種方法:

1. A 表的記錄導出爲一條條分號隔開的 insert 語句,而後執行插入到 B 表中
2. 創建數據庫間的 dblink,而後用 create table B as select * from A@dblink where ...,或 insert into B select * from A@dblink where ...
3. exp A 表,再 imp 到 B 表,exp 時可加查詢條件
4. 程序實現 select from A ..,而後 insert into B ...,也要分批提交
5. 再就是本篇要說到的 Sql Loader(sqlldr) 來導入數據,效果比起逐條 insert 來很明顯

第 1 種方法在記錄多時是個噩夢,需三五百條的分批提交,不然客戶端會死掉,並且導入過程很慢。若是要不產生 REDO 來提升 insert into 的性能,就要下面那樣作:

html

alter table B nologging;  web

insert /* +APPEND */ into B(c1,c2) values(x,xx);  sql

insert /* +APPEND */ into B select * from A@dblink where .....;  數據庫

好啦,前面簡述了 Oracle 中數據導入導出的各類方法,必定還有更高明的。下面重點講講 Oracle  的 Sql Loader (sqlldr) 的用法。

在命令行下執行 Oracle  的 sqlldr 命令,能夠看到它的詳細參數說明,要着重關注如下幾個參數:

userid -- Oracle 的 username/password[@servicename]
control -- 控制文件,可能包含表的數據
-------------------------------------------------------------------------------------------------------
log -- 記錄導入時的日誌文件,默認爲 控制文件(去除擴展名).log
bad -- 壞數據文件,默認爲 控制文件(去除擴展名).bad
data -- 數據文件,通常在控制文件中指定。用參數控制文件中不指定數據文件更適於自動操做
errors -- 容許的錯誤記錄數,能夠用他來控制一條記錄都不能錯
rows -- 多少條記錄提交一次,默認爲 64
skip -- 跳過的行數,好比導出的數據文件前面幾行是表頭或其餘描述

還有更多的 sqlldr 的參數說明請參考:sql loader的用法

用例子來演示 sqlldr 的使用,有兩種使用方法:

1. 只使用一個控制文件,在這個控制文件中包含數據
2. 使用一個控制文件(做爲模板) 和一個數據文件

通常爲了利於模板和數據的分離,以及程序的不一樣分工會使用第二種方式,因此先來看這種用法。數據文件能夠是 CSV 文件或者以其餘分割符分隔的,數據文件能夠用 PL/SQL Developer 或者 Toad 導出,也能夠用 SQL *Plus 的  spool 格式化產出,或是 UTL_FILE 包生成。另外,用 Toad 還能直接生成包含數據的控制文件。

首先,假定有這麼一個表 users,並插入五條記錄:

併發

create table users(      oracle

user_id number,             --用戶 ID    app

user_name varchar2(50),     --用戶名    函數

login_times number,         --登錄次數    post

last_login              date--最後登陸日期性能

);

 

 

INSERT INTO users
VALUES
    (1,
     'Unmi',
     3,
     SYSDATE);
INSERT INTO users
VALUES
    (2,
     NULL,
     5,
     to_date('2008-10-15', 'YYYY-MM-DD'));
INSERT INTO users
VALUES
    (3,
     '隔葉黃鶯',
     8,
     to_date('2009-01-02', 'YYYY-MM-DD'));
INSERT INTO users
VALUES
    (4,
     'Kypfos',
     NULL,
     NULL);
INSERT INTO users
VALUES
    (5,
     '不知秋',
     1,
     to_date('2008-12-23', 'YYYY-MM-DD'));


第二種方式: 使用一個控制文件(做爲模板) 和一個數據文件

1) 創建數據文件,咱們這裏用 PL/SQL Developer 導出表 users 的記錄爲 users_data.csv 文件,內容以下:

 

"   ","USER_ID","USER_NAME","LOGIN_TIMES","LAST_LOGIN"  

"1"  ,"1","Unmi","3","2009-1-5 20:34:44"

"2"  ,"2","","5","2008-10-15"

"3"  ,"3","隔葉黃鶯","8","2009-1-2"

"4"  ,"4","Kypfos","",""

"5","5","不知秋","1","2008-12-23"  
2) 創建一個控制文件 users.ctl,內容以下:

OPTIONS (skip=1,rows=128) -- sqlldr 命令顯示的選項能夠寫到這裏邊來,skip=1 用來跳過數據中的第一行  

LOAD DATA  INFILE    "users_data.csv"--指定外部數據文件,能夠寫多個 INFILE "another_data_file.csv" 指定多個數據文件--這裏還可使用 BADFILE、DISCARDFILE 來指定壞數據和丟棄數據--的文件,  

truncate   --操做類型,用 truncate table 來清除表中原有記錄

INTO   TABLE users -- 要插入記錄的表

Fields terminated     by","-- 數據中每行記錄用 "," 分隔

Optionally enclosed by '"' -- 數據中每一個字段用 '"' 框起,好比字段中有 "," 分隔符時    

trailing nullcols --表的字段沒有對應的值時容許爲空

(    virtual_column FILLER,   --這是一個虛擬字段,用來跳過由 PL/SQL Developer 生成的第一列序號  

user_id number,   --字段能夠指定類型,不然認爲是 CHARACTER 類型, log 文件中有顯示  

user_name,    

login_times,    

last_login     DATE"YYYY-MM-DD HH24:MI:SS"-- 指定接受日期的格式,至關用 to_date() 函數轉換

)  

 

說明:在操做類型 truncate 位置可用如下中的一值:
1) insert     --爲缺省方式,在數據裝載開始時要求表爲空
2) append  --在表中追加新記錄
3) replace  --刪除舊記錄(用 delete from table 語句),替換成新裝載的記錄
4) truncate --刪除舊記錄(用 truncate table 語句),替換成新裝載的記錄

3) 執行命令:

sqlldr dbuser/dbpass@dbservice control=users.ctl

在 dbservice 指示的數據庫的表 users 中記錄就和數據文件中的同樣了。

執行完 sqlldr 後但願能留意一下生成的幾個文件,如 users.log 日誌文件、users.bad 壞數據文件等。特別是要看看日誌文件,從中可以讓你更好的理解 Sql Loader,裏面有對控制文件的解析、列出每一個字段的類型、加載記錄的統計、出錯緣由等信息。

第一種方式,只使用一個控制文件在這個控制文件中包含數據

1) 把 users_data.cvs 中的內容補到 users.ctl 中,並以 BEGINDATA 鏈接,還要把 INFILE "users_data.csv" 改成 INFILE *。同時爲了更大化的說明問題,把數據處理了一下。此時,完整的 users.ctl 文件內容是:

OPTIONS (skip=1,rows=128) -- sqlldr 命令顯示的選項能夠寫到這裏邊來,skip=1 用來跳過數據中的第一行  

LOAD DATA  INFILE *    -- 由於數據同控制文件在一塊兒,因此用 * 表示

append      -- 這裏用了 append 來操做,在表 users 中附加記錄 

INTO TABLE users  when   LOGIN_TIMES<>'8'  -- 還能夠用 when 子句選擇導入符合條件的記錄

Fields terminated    by","

trailing nullcols  (    

virtual_column FILLER,   --跳過由 PL/SQL Developer 生成的第一列序號  

user_id   "user_seq.nextval"--這一列直接取序列的下一值,而不用數據中提供的值  

user_name   "'Hi '||upper(:user_name)",--,還能用SQL函數或運算對數據進行加工處理  

login_times terminated    by","NULLIF(login_times='NULL') --可爲列單獨指定分隔符  

last_login     DATE"YYYY-MM-DD HH24:MI:SS"NULLIF (last_login="NULL"-- 當字段爲"NULL"時就是 NULL)  

BEGINDATA   --數據從這裏開始   

,USER_ID,USER_NAME,LOGIN_TIMES,LAST_LOGIN  

1,1,Unmi,3,2009-1-5 20:34  

2,2,Fantasia,5,2008-10-15  

3,3,隔葉黃鶯,8,2009-1-2  

4,4,Kypfos,  NULL,NULL

5,5,不知秋,1,2008-12-23  

 

2) 執行同樣的命令:

sqlldr dbuser/dbpass@dbservice control=users.ctl

好比,在控制檯會顯示這樣的信息:

C:\>sqlldr dbuser/dbpass@dbservice control=users.ctl

SQL*Loader: Release 9.2.0.1.0 - Production on 星期三 1月 7 22:26:25 2009

Copyright (c) 1982, 2002, Oracle Corporation.  All rights reserved.

達到提交點,邏輯記錄計數4
達到提交點,邏輯記錄計數5

上面的控制文件包含的內容比較複雜(演示目的),請根據註釋理解每一個參數的意義。還能由此發掘更多用法。

最後說下有關 SQL *Loader 的性能與併發操做

1) ROWS 的默認值爲 64,你能夠根據實際指定更合適的 ROWS 參數來指定每次提交記錄數。(體驗過在 PL/SQL Developer 中一次執行幾條條以上的 insert 語句的情形嗎?)

2)常規導入能夠經過使用 INSERT語句來導入數據。Direct導入能夠跳過數據庫的相關邏輯(DIRECT=TRUE),而直接將數據導入到數據文件中,能夠提升導入數據的性能。固然,在不少狀況下,不能使用此參數(若是主鍵重複的話會使索引的狀態變成UNUSABLE!)。

3) 經過指定 UNRECOVERABLE選項,能夠關閉數據庫的日誌(是否要 alter table table1 nologging 呢?)。這個選項只能和 direct 一塊兒使用。

4) 對於超大數據文件的導入就要用併發操做了,即同時運行多個導入任務.

  sqlldr   userid=/   control=result1.ctl   direct=true   parallel=true   
  sqlldr   userid=/   control=result2.ctl   direct=true   parallel=true   
  sqlldr   userid=/   control=result2.ctl   direct=true   parallel=true  

  當加載大量數據時(大約超過10GB),最好抑制日誌的產生:   
  
  SQL>ALTER   TABLE   RESULTXT   nologging; 
  
  這樣不產生REDO LOG,能夠提升效率。而後在 CONTROL 文件中 load data 上面加一行:unrecoverable,  此選項必需要與DIRECT共同應用。   
  
  在併發操做時,ORACLE聲稱能夠達到每小時處理100GB數據的能力!其實,估計能到 1-10G 就算不錯了,開始可用結構 相同的文件,但只有少許數據,成功後開始加載大量數據,這樣能夠避免時間的浪費。

(注意:通常只能用ASCII碼形式,切記要轉換編碼,否則導入數據爲空)(ftp上傳csv文件的傳輸類型選擇ascii)

參考:1. Oracle SQL*Loader  -- 英文,Sql Loader 的官方使用說明,包含多種類型的  Demo
        2. sql loader的用法  -- 列出了 sql loader 的選擇參數的中文說明
        3. 使用SQL Loader導入大量數據,避免使用SQL頻繁寫庫 -- 一個簡單的例子,快帶了解 Sql Loader 的用法
        4. Oracle SQL Loader的詳細語法
        5. oracle sql loader全攻略 -- 還算名符其實。並講了如何用 SQL *Plus 的  spool 或 UTL_FILE 包生成數據文件
        6. SQL*Loader Control File Reference   -- 英文,控制文件使用參考
        7. 學習oracle sql loader 的使用 
        8. 用sqlloader(sqlldr)裝載LOB數據  -- LOB 的內類是一個外部文件,用 sql loader 導入到數據庫
        9. SQLLDR直接加載幾個參數的測試
        10.Maximizing SQL*Loader Performance

我試了一下optionally enclosed by '"'

左邊沒引號右邊有引號:成功,原樣導入 (原樣導入)
111"
222""
333"""

左邊有引號右邊沒引號:失敗, second enclosure string not present (失敗)
"44
""555
"""666

左右有相等的奇數個引號,成功,引號數=2n+1時導入數據帶有n個引號 (只導入值沒引號)
"777"
"""888"""

左右有相等的偶數個引號,失敗, no terminator found after TERMINATED and ENCLOSED field (失敗)
""999""
""""AAA""""

一邊奇數一邊偶數:失敗, 錯誤信息爲上述兩種  (失敗)
"BBB""
""CCC"
"""DDD""
""EEE"""

兩邊不等的偶數:失敗, no terminator found after TERMINATED and ENCLOSED field (失敗)
""FFF""""
""""GGG""

兩邊不等的奇數:成功,引號數=2n+1時導入數據帶有n個引號 (成功,此處引號數值爲一邊引號多的爲主,用2N+1=單邊最大引號)
"HHH"""
"""III"

總結:要麼左邊不能帶引號;若是有引號左右都必須爲奇數個
相關文章
相關標籤/搜索