SQL*Loader 是 Oracle 高效載入外部格式化文字資料的核心工具,常與 SPOOL 導出配合實現資料遷移、ETL、備份恢復。本文詳細解析控制檔語法、資料格式、常規/直接路徑模式、SPOOL 導出技巧,並提供生產級 Shell 自動化腳本。
sqlldr userid=user/pwd control=emp.ctl data=emp.dat bad=emp.bad log=emp.log
LOAD DATA
INFILE *
APPEND
INTO TABLE emp
FIELDS TERMINATED BY '|'
(
no FLOAT EXTERNAL,
name CHAR(20),
age INTEGER EXTERNAL,
duty CHAR(1),
salary FLOAT EXTERNAL,
upd_ts DATE(14) "YYYYMMDDHH24MISS"
)
BEGINDATA
100000000003|Mulder|000020|1|000000005000|20020101000000
100000000004|Scully|000025|2|000000008000|20020101235959
| 格式 | INFILE 語法 | 特徵 | 適用場景 |
|---|---|---|---|
| 固定長度 | INFILE 'file.dat' "FIX 11" | 每筆記錄固定位元組長 | 大型批次、效能優先 |
| 可變長度 | INFILE 'file.dat' "VAR 3" | 前置長度欄位(如3位元組)+資料 | 欄位長度差異大 |
| 串流記錄 | INFILE 'file.dat' "STR '|\n'" | 以特定分隔符結尾(如 | 換行) | 文字報表、跨平台交換 |
| 特性 | Conventional Path | Direct Path (DIRECT=TRUE) |
|---|---|---|
| 機制 | SQL INSERT 路徑,經緩衝區、產生 Redo、觸發 Trigger | 繞過 SQL 層,直接寫入資料檔,最小化 Redo |
| Commit/ Save | COMMIT (ROWS 參數控制頻率) | SAVE (資料直接寫入,無回滾段) |
| 約束檢查 | 全部檢查 | 僅 PK/UK/NN,不檢查 FK/Check |
| Trigger | 觸發 INSERT Trigger | 不觸發 |
| 叢集表 | 支援 | 不支援 |
| 並發 | 其他用戶可修改 | 獨佔,其他用戶不可變更 |
| 效能 | 標準 | 大幅優於常規路徑 (大數據量首選) |
SET NEWPAGE NONE HEADING OFF SPACE 0 PAGESIZE 0
SET TRIMOUT ON TRIMSPOOL ON LINESIZE 2500
-- LINESIZE 足夠大防截斷,TRIMSPOOL 移除尾部空格
-- Windows 下建議用 CMD 執行 SQL*Plus 最小化視窗,避免 PL/SQL Developer 導出緩慢
SPOOL /path/export.dat
SELECT col1||'|'||col2||'|'||col3 FROM table_name;
SPOOL OFF
注意: 包含換行符的欄位需預先清洗/轉義,確保單行一筆記錄。
#!/bin/ksh
# 用法: unloadtable table_name username password
if [ $# -ne 3 ]; then echo "usage: unloadtable tablename username password"; exit 1; fi
TBL=$1; USR=$2; PWD=$3
TMP_COL=/tmp/${TBL}.col
TMP_SEL=/tmp/${TBL}.sel
# 1. 產生欄位清單 SQL
cat > ${TMP_COL} < ${TMP_SEL} < ${TBL}_tmp.dat
awk '{print $0}' ${TBL}_tmp.dat > ${TBL}.dat
rm -f ${TBL}_tmp.dat ${TMP_COL} ${TMP_SEL}
#!/bin/ksh
# 用法: loadtable table_name username password
if [ $# -ne 3 ]; then echo "usage: loadtable tablename username password"; exit 1; fi
TBL=$1; USR=$2; PWD=$3
TMP_COL=/tmp/${TBL}.colsql
TMP_CTL=/tmp/${TBL}.ctl
TMP_SQL=/tmp/${TBL}.sql
# 1. 取得欄位清單
cat > ${TMP_COL} < ${TMP_CTL} <> ${TMP_CTL}
# 3. 清空目標表並載入
echo "TRUNCATE TABLE ${TBL};" > ${TMP_SQL}
sqlplus ${USR}/${PWD} @${TMP_SQL}
sqlldr ${USR}/${PWD} DATA=${TBL}.dat CONTROL=${TMP_CTL} LOG=/tmp/${TBL}.log
# 清理暫存檔
rm -f ${TMP_COL} ${TMP_CTL} ${TMP_SQL}