由酸菜鱼记录,所有代码均经过测试.只是部分代码的效果在不同平台上会出现差异!有问题请:1#w1520.com[#替换成@],或者:提交建议


SQL*Loader总结

认识SQL*Loader SQL*Loader体系结构 一千零一十一个怎么办 100万条记录的数据加载


本处使用的配置:

  • Red hat Server 6.4 _ X64 [英文版]
  • Oracle 11G R2 _X64[英文版]

认识SQL*Loader

SQL*Loader是一个命令行下的操作工具,对应的操作系统命令是SQLLDR,注意Linux/UNIX环境中对于命令的大小写敏感,执行的命令应为小写:sqlldr.

示例: 为Oracle添加几笔数据(Oracle数据库必须已经正常启动): 在当前目录新建一个文件:ldr_case1.ctl :

注意:文件名和文件类型任意.

保存如下内容:

LOAD DATAINFILE *INTO TABLE BONUSFIELDS  TERMINATED BY ","(ENAME,JOB,SAL)BEGINDATASMITH,CLEAK,3904ALLEN,SALESMAN,2891WARD,SALESMAN,3128KING,PRESIDENT,2523---------//code end.

然后执行如下命令:


sqlldr scott/TIGER CONTROL=ldr_case1.ctl //提交记录到数据库

然后马上连接到数据库看一下:


SQLPLUS scott/TIGERSELECT * FROM BONUS;//...输出上述数据.

SQL*Loader体系结构

控制文件

LOAD DATA-----------我是分割符--------------INFILE *INTO TABLE BONUSFIELDS    TERMINATED BY ","(ENAME,JOB,SAL)BEGINDATA-----------我是分割符--------------SMITH,CLEAK,3904ALLEN,SALESMAN,2891WARD,SALESMAN,3128KING,PRESIDENT,2523

  1. 第一部分:控制文件一般以此开头(控制文件的语法非常复杂,一般是以此开头,不是说只能以此开头,比如LOAD DATA前可指定UNRECOVERABLE或RECOVERABLE来控制此次加载的数据是否可恢复,或者指定CONTINUE_LOAD,表示继续加载.更多控制文件语法的大全可以参考官方文档.这里只对常用功能进行介绍.)
  2. 中间部分:这里是真正的控制部分,下面分解开来,逐条介绍:
    >:INFILE:表示数据文件位置,如果值为*,表示数据就在控制文件中,本例中没有单独的数据文件,对于大多数加载而言,都会将数据文件与控制文件分离.>:INTO TABLE tbl_name: tbl_name 即数据要加载到的目标表,该表再你执行SQLLDR命令之前必须已经创建.>> INTO 前还有一些很有意思的参数需要说明:>>>:INSERT :向表中插入数据,表必须为空,如果表非空的话,执行SQLLDR命令时会报错,默认就是INSERT参数.>>>:APPEND :向表中追加数据,不管表中是否有数据.>>>:REPLACE :替换表中数据,相当于先DELETE表中全部数据,然后再INSERT.>:FIELDS TERMINATED BY "," : 设置数据部分字符串的分隔值,这里设置为逗号(,)分隔,当然也可以换成其他任意可见字符,只要确定那是数据行中的分割符就行.>:(ENAME,JOB,SAL) :要插入的表的列名,这里需要注意的是列名要与表中列名完全相同,列的顺序可以与表中列顺序不同,但是必须与数据部分的列一一对应.>:BEGINDATA :表示以下为待加载数据,仅当INFILE指定为*时有效.
    
  3. 数据部分:演示时为了简化步骤,将数据部分与控制部分都放在控制文件中,通常这部分是独立存在于一个文本文件中.如果是独立的数据文件,只需要将控制文件中INFILE参数后面的*改为数据文件的文件名即可.

日志文件

在默认情况下,SQLLDR命令再执行过程中,会自动产生一个与控制文件同名的日志文件,文件扩展名为.log,日志文件中记录了加载过程中的各项统计信息,如一些初始化参数,读取的记录数,成功加载的记录数,加载用时等.

//此产生的日志文件存放于:ldr_case1.log

错误文件

SQLLDR命令在执行过程中,还会产生一个同名的错误文件,文件扩展名为.bad(如果DBA不显式指定的话.)错误文件中数据的格式与数据文件完全相同.

废弃文件

除了日志文件和错误文件,执行SQLLDR命令时还有可能生成一个同名的废弃文件,文件扩展名为.dsc(在默认情况下不会有,必须在执行SQLLDR命令时显式指定废弃文件,并确实存在不符合导入逻辑的记录)


//~SQL*Loader 体系结构图 //~ 存放于本目录下的images文件夹.[名为:5_2sqlldr.png]

一千零一十一个怎么办

给我的是个Excel文件怎么办

注意:如果是Excel文件,则可以选择用csv格式 [以逗号分割]保存文件,然后用上面的方式导入. .xls文件单个Sheet最大行数不超过65536行.

要加载的文件不是以逗号分隔怎么办

有两种方式可以参考:

  1. 修改控制文件,将分隔符替换为逗号.
  2. 修改控制文件,将FIELDS TERMINATED BY 的值修改为实际的分割符.

要加载的数据中包含分隔符怎么办

提供的数据格式如下:


SMITH,CLEAK,3904
ALLEN,"SALER,M",2891
WARD,"SALER,""S""",3128
KING,PRESIDENT,2523
--ldr_case2.ctl

修改控制文件:


LOAD DATA
INFILE ldr_case2.ctl
TRUNCATE INTO TABLE BONUS
FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"'
(ENAME,JOB,SAL)
BEGINDATA

数据文件没有分隔符怎么办

例如:提供数据文件中的数据都是以下的格式:


SMITH CLEAK 3904
ALLEN SALESMAN 2891
WARD SALESMAN 3128
KING PRESIDENT 2523

示例文件保存为数据文件:oracledata3.data

按照专业的叫法,这是定长字符串,不要紧的.SQLLDR中处理定长字符串也轻而易举.

针对此例,我们将控制文件修改如下:


LOAD DATA
INFILE oracledata3.data
TRUNCATE INTO TABLE BONUS
(
ENAME position(1:5);
JOB position(7:15);
SAL Position(17:20)
)
BEGINDATA

控制文件保存为:ldr_case3.ctl

position关键字用来指定列的开始和结束位置,如JOB position(7:15)是指从第7个字符开始截止到第15个字符作为ENAME列的列值.position的写法也很灵活,要实现上述功能还可以换成下列几种形式:

  1. position(*+2:15):直接指定数值的方式叫做绝对偏移量,如果使用*号,专业名词叫相对偏移量,表示上一个字段从哪里结束,这次就从哪里开始.相对偏移量也可以再做运算,比如(*+2:15)就表示从上次结束的位置+2的地方开始.
  2. position(*)char(9):这种相对偏移量+类型和长度的优势在于,你只需要为第一列指定位置开始,其他列只需要指定列的长度就可以了,实际使用中比较省事.

数据文件中的列比要导入的表中的列少怎么办

提出这样的问题,说明你没有认真看我们前面的实例.重新看一下表结构:

Name                    Null?    Type----------------------------------------- -------- --ENAME                          VARCHAR2(10)JOB                         VARCHAR2(9)SAL                          NUMBERNUMBER

之前的诸多演示,正是在数据文件中列比表要少的环境下创建的.这说明列少不怕,关键是看控制文件中的配置.考虑下面一种情况,如果缺少的列必须赋值又怎么办?(修改一下控制文件即可):

LOAD DATAINFILE oracledata3.dataTRUNCATE INTO TABLE BONUS(ENAME position(1:5),JOB position(7:15),SAL position(17:20),"0")BEGINDATA

示例代码保存为控制文件 ldr_case3.ctl

输出数据库数据.

可以再玩点更有难度的,根据SAL的值设置列的值,修改控制文件如下:

LOAD DATAINFILE oracledata4.dataTRUNCATE INTO TABLE BONUS(ENAME position(1:5),JOB position(7:15),SAL position(17:20),"substr(:SAL,1,1)")BEGINDATA

插入数据.

输出数据库数据

ENAME       JOB          SAL       ---------- --------- ---------- ----------SMITH      CLEAKMAN     904      9ALLEN    SALESMAN     891      8WARDA    SALESMAN     128      1KINGA    PRESIDENT       2523      2

这里列的值根据SAL列值而定,我们通过一个SQL中的函数substr取SAL值的第一列,赋予列,当然这只是一个示例.DBA可以根据实际需求进行适当的修改,通过SQL中的函数可以实现很多很有意思的转换,
也许能够为你省下很大力气.而且如果现有函数无法实现,甚至可以通过PL/SQL编写自定义函数,然后在SQLLDR的控制文件中调用,调用方式与系统自带函数方式完全相同.这样就可以根据需求对要加载的列做更灵活的处理.

数据文件中的列比要导入的表中的列多怎么办

如果数据文件中的列比要导入的表中的列少,处理的时候可能麻烦些,多了反倒更简单.针对不同情况,一般有以下两种处理方式:

1.修改数据文件,将多余的数据删除,不过以这种方式处理,小数据量时还算可行,一旦数据文件较大,几百兆甚至上千兆,修改数据文件耗时耗力.这时我们就需要Plan B.

2.比如,数据文件如下:

-------------------------------------示例数据文件:

SMITH    7369 CLERK  800 20ALLEN 7499 SALESMAN   1600 30WARD 7521 SALESMAN   1250 30SMITH    7369 CLERK  800 20ALLEN 7499 SALESMAN   1600 30WARD 7521 SALESMAN   1250 30SMITH    7369 CLERK  800 20ALLEN 7499 SALESMAN   1600 30WARD 7521 SALESMAN   1250 30SMITH    7369 CLERK  800 20ALLEN 7499 SALESMAN   1600 30WARD 7521 SALESMAN   1250 30//----------------------------------end DATA.

示例文件保存为:oracledata4.data

我们希望导入第1,3,4列而跳过2,5两列(注意这里指的不是字符列),创建控制文件:

LOAD DATAINFILE oracledata4.dataTRUNCATE INTO TABLE BONUS(ENAME position(1:6),TCOL FILLER position(8:11),JOB position(13:21),SAL position(23:26))BEGINDATA

SQLLDR的控制文件中对列定义时支持FILLER关键字,可以用来指定过滤列,在上述控制文件中,我们就使用该关键字来过滤列,相当于第8到第11列之间的数据不导入.

事实上由于此处为定长字串,我们再控制文件中指定的position参数,已经限定了读取的内容,你甚至可以删除控制文件中TCOL FILLER position(8:11)那行.

结果符合要求,不过如果数据文件中字符串不是定长格式,而是通过跟分隔符来处理的,那控制文件中就需要注意,如数据文件如下:

SMITH,7369,CLERK,800,20ALLEN,7499,SALESMAN,1600,30WARD,7521,SALESMAN,1250,30SMITH,7369,CLERK,800,20ALLEN,7499,SALESMAN,1600,30WARD,7521,SALESMAN,1250,30SMITH,7369,CLERK,800,20ALLEN,7499,SALESMAN,1600,30WARD,7521,SALESMAN,1250,30SMITH,7369,CLERK,800,20ALLEN,7499,SALESMAN,1600,30WARD,7521,SALESMAN,1250,30

-->数据文件保存为:oracledata5.data

创建控制文件,此时控制文件必须指定FILLER,不然列值就有可能不对应,例如:创建控制文件如下:

LOAD DATAINFILE oracledata5.dataTRUNCATE INTO TABLE BONUSFIELDS TERMINATED BY ","(ENAME,TCOL FILLER,JOB,SAL)BEGINDATA

-->控制文件保存为:ldr_case7.ctl

-->执行SQLLDR

输出数据库数据

//------------------------------SQL> SELECT * FROM BONUS;ENAME       JOB          SAL       ---------- --------- ---------- ----------SMITH      CLERK        800ALLEN       SALESMAN    1600WARD    SALESMAN    1250SMITH       CLERK        800ALLEN       SALESMAN    1600WARD    SALESMAN    1250SMITH       CLERK        800ALLEN       SALESMAN    1600WARD    SALESMAN    1250SMITH       CLERK        800ALLEN       SALESMAN    1600ENAME       JOB          SAL       ---------- --------- ---------- ----------WARD       SALESMAN    125012 rows selected.

提供了多个数据文件,要导入同一张表怎么办

通常对于逻辑比较复杂的系统可能存在这种情况,因为导出的数据来源于多个系统,因此可能提供给DBA的也是多个数据文件.没有关系,先不要急着抱怨,像SQL*Loader这么有历史底蕴的工具,
什么风雨没见过,这种小case.人家早就已经预见到了,并不需要你执行多次加载,只需要在控制文件中做适当配置即可.不过有一点非常重要,提供的数据文件中的数据存放格式必须完全相同.

下面简单演示,之前老是用BONUS,这里换个表把,新建一个MANAGER表:

    CREATE TABLE MANAGER(MGRNO NUMBER,MNAME VARCHAR2(30),JOB VARCHAR2(30),REMARK VARCHAR2(4000));

有多个数据文件,分别如下[已经在表中存在的数据]:

示例文件保存为数据文件oracledata6.data

       10,SMITH,SALES,MANAGER11,ALLEN.W,TECH,MANAGER16,BLAKE,HR,MANAGER

示例代码保存为数据文件oracledata6_1.data

12,WARD,SERVICE,MANAGER13,TURNER,SELLS,DIRECTOR15,JAMES,HR,DIRECTOR

示例代码保存为数据文件oracledata6_2.data

17,MILLER,PRESIDENT

创建控制文件,只需要指定多个INFILE参数即可,如下所示:

LOAD DATAINFILE oracledata6.dataINFILE oracledata6_1.dataINFILE oracledata6_2.dataTRUNCATE INTO TABLE MANAGERFIELDS TERMINATED BY ","(MGRNO,MNAME,JOB)BEGINDATA

执行命令sqlldr.

输出数据库数据

同一个数据文件,要导入不同表怎么办

控制文件提供了多种逻辑判断方式,只要能把逻辑清晰地描述出来,SQL*Loader就能按照指定的逻辑加载.

举个例子,待导入的数据文件如下:

BON SMITH  CLEAK  3904BON ALLEN  SALER,M  2891BON WARD  SALER,“S”  3128BON KING  PRESIDENT  2523MGR  10  SMITH  SALES  MANAGERMGR  11  ALLEN.W  TECH  MANAGERMGR  16  BLAKE  HR  MANAGERTMP SMITH 7369   CLERK     800   20 TMP ALLEN 7499   SALESMAN  1520  30TMP WARD  7521   SALESMAN  1250  30TMP JONES 7566   MANAGER   2975  20

-->示例代码保存数据文件为:oracledata7.data

需求是将MGR开头的记录导入MANAGER表,以BON开头的记录导入BONUS表,其他记录存入废弃文件中:

LOAD DATAINFILE oracledata7.dataDISCARDFILE oracledata7.dscTRUNCATEINTO TABLE BONUSWHEN TAB='BON'(TAB FILLER POSITION(1:3),ENAME POSITION(5,8),JOB POSITION(*+1:18),SAL POSITION(*+1))INTO TABLE MANAGERWHEN TAB = 'MGR'(TAB FILLER POSITION(1:3),MGRNO POSITION(4:5),MNAME POSITION(7:13),JOB POSITION(*+1))BEGINDATA

->示例代码保存为:ldr_case10.ctl

虽然这个控制文件看起来比之前的都要复杂,但只有一个新语法,即WHEN关键字,我们这里通过WHEN来实现判断,很容易理解.同时,指定了DISCARDFILE参数,
以生成不满足加载条件的废弃文件,如果你有心,不妨等执行完SQLLDR命令后查看ldr_case10.dsc文件和ldr_case10.log文件.

注意:控制文件中WHEN逻辑判断不支持OR关键字,因此如果你的判断条件有多个,则只能通过AND连接,而不能直接使用OR.

数据文件前N行不想导入怎么办

假如某天你接到一项数据加载需求,用户提供了一份100万行的数据文件,告诉你导后50万行,恭喜,你接到了一个正常的需求.

实现的方式较多,比如修改数据文件,只保留后50万行(Windows 下借助Editplus这类文本工具可以轻松实现,Linux/UNIX下通过TAIL等命令也可以轻易实现).

如果你人很懒,不想修改文件,那正合SQLLDR胃口,人家早早的就提供好了SKIP参数专用于满足此类需求.

例如:提供的数据文件如下:

SQL> SELECT ENAME,MGR,JOB,SAL FROM EMP;//^=10ENAME         MGR JOB          SAL---------- ---------- --------- ----------1:6 7-11 15:23 26:33 [22-31值太大,超过10个字节!!报错!!]123456789^123456789^123456789^123456789^12SMITH67902     CLERK  800ALLEN67698     SALESMAN  1600WARD66698      SALESMAN     1250JONES67839     MANAGER  2975MARTIN7698     SALESMAN     1250BLAKE67839     MANAGER  2850CLARK67839     MANAGER  2450SCOTT67566     ANALYST  3000KING66PRESIDENT 5000TURNER7698     SALESMAN     1500ADAMS67788     CLERK    1100

示例代码保存为数据文件oracledata8.data


//前三行不导入,从第四行开始导入.LOAD DATAINFILE oracledata8.dataTRUNCATE INTO TABLE BONUS(ENAME position(1:6),TCOL FILLER position(18:21),JOB  position(23:31),SAL position(39:42))BEGINDATA

查看导入结果:


SQL> SELECT * FROM BONUS;ENAME      JOB          SAL       ---------- --------- ---------- ----------SMITH      LERK         800ALLEN       ALESMAN     1600WARD    LESMAN      1250JONES       ANAGER      2975MARTIN      SALESMAN    1250BLAKE       ANAGER      2850CLARK       ANAGER      2450SCOTT       NALYST      3000KING    ESIDENT     5000TURNER      SALESMAN    1500ADAMS       LERK        1100

如果用户要求只加载第X~XX行的记录,SQLLDR还有一个参数叫LOAD,配置LOAD参数即可轻松实现.

示例:依旧使用上述数据,需求更改为,只导入第4~9行的数据:

执行命令:SQLLDR SCOTT/TIGER CONTROL=ldr_case.ctl SKIP=4 LOAD=6

要加载的数据中有换行符怎么办

由于标准换行符也是SQLLDR识别数据行结束的标注符,因此要将含换行符的数据加载到表中稍复杂一点点,而且需要根据实际情况来处理,不同情况的处理方式也不一样,但基本思路是相同的,就是要同SQLLDR指明什么时候才需要进行换行操作.

手工指定的换行符

在手工指定换行符的情况下,数据文件中的换行符并不是标准的换行标志,而是用户自定义的一个标识字符(或多个字符组成),这种情况的处理比较简单,如数据文件如下:


10,SMITH,SALES MANAGER,This is SMITH.  \nHe is a Sales Manager.11,ALLEN.W,TECH MANAGER,This is ALLEN.W. \nHe is a tech Manager.16,BLAKE,HR MANAGER,This is BLAKE. \nHe is a Hr Manager.

示例代码保存为数据文件 oracledata10.data

我们可以通过控制文件,在数据加载前处理remark列的数据,将用户指定的"\n"字符替换为chr(10),即标准换行符,创建控制文件如下:

LOAD DATAINFILE oracledata10.dataTRUNCATE INTO TABLE MANAGERFIELDS TERMINATED BY ","(MGRNO,MNAME,JOB,REMARK "replace(:remark, '\\n',chr(10))")BEGINDATA

示例代码保存为控制文件:ldr_case12.ctl

这里需要注意的是,替换时必须指定"\\n"而不只是"\n",因为"\n"会被SQLLDR识别成换行符并转换成换行标志,这样可能导致数据加载出错.而"\"是默认转义符,指定该转义符后SQLLDR就会将"\n"识别成普通字符了.

指定FIX属性处理换行符(定长数据文件专用)

数据文件如下:

10,SMITH,SALES MANAGER,This is SMITH.He is a Sales Manager.11,ALLEN.W,TECH MANAGER,This is ALLEN.W.He is a tech Manager.16,BLAKE,HR MANAGER,This is BLAKE.He is a Hr Manager.

示例代码保存为数据文件: oracledata11.data

创建控制文件如下:

LOAD DATAINFILE oracledata11.data "fix 68"TRUNCATE INTO TABLE MANAGER(MGRNO position(1:2),MNAME position(*+1:10),JOB position(*+1:24),REMARK position(*+1:65))BEGINDATA

示例代码保存为控制文件 ldr_case13.ctl

指定VAR属性处理换行符(行头部标识换行)

前面提到的INFILE 关键字还支持VAR属性,语法格式为INFILE filename "var n",n的值不能超过40,否则会报错,如果不指定n,则默认值为5.

本小节就演示通过这种方式处理换行符.总的来说,这确实是相当有才的一种方式,首先通过VAR属性在每行开头指定一个固定长度的字符串,该字符串指明该行的长度,通过这种方式支持变长字符串.

下面演示一下,数据文件如下:


06310,SMITH,SALES MANAGER,This is SMITH.He is a Sales Manager.06511,ALLEN.W,TECH MANAGER,This is ALLEN.W.He is a tech Manager.05516,BLAKE,HR MANAGER,This is BLAKE.He is a Hr Manager.

示例代码保存为数据文件 oracledata12.data

创建控制文件如下:

LOAD DATAINFILE oracledata12.data "var 3"TRUNCATE INTO TABLE MANAGERFIELDS TERMINATED BY ","(MGRNO,MNAME,JOB,REMARK)BEGINDATA

示例代码保存为控制文件: ldr_case14.ctl

注意:这两种方式其实并不方便,因为每个操作系统的换行标识符 也不同,比如,在Windows环境下换行标志由"回车(13)+换行CHR(10)"两个 字节组成,而Linux/UNIX环境则是"换行CHR(10)"一个字节,也就是说指定了长度 也不方便转换.[下面介绍的方法更易于操作,也更可行一些]

指定STR属性处理换行符(行尾部标识换行)

这种方式也需要先对数据文件做处理,在记录换行除打上一个标记,比如“|”(当然你也可以定义为其他字符,但注意不要与要导入的数据有冲突),这样SQLLDR见到该字符就知道换行的时候到了.

由于单个字符出现在导入数据中的机率较高,因此简易换行标志尽可能由多个字符组成,通常习惯于定义“字符+换行符”作为新的换行标记,这里我们也采用这种方式.

例如:数据文件如下:

10,SMITH,SALES MANAGER,This is SMITH.He is a Sales Manager.|11,ALLEN.W,TECH MANAGER,This is ALLEN.W.He is a Tech Manager.|16,BLAKE,HR MANAGER,This is BLAKE.He is a Hr Manager.|

示例代码保存为数据文件: oracledata13.data

创建控制文件如下:

LOAD DATAINFILE oracledata13.data "str '|'"TRUNCATE INTO TABLE MANAGERFIELDS TERMINATED BY ","(MGRNO,MNAME,JOB,REMARK)BEGINDATA

控制文件保存为: ldr_case15.ctl

STR属性中支持两种字符指定方式:

'char_string':普通字符,即标准的可见字符,不过也有写不可见字符可以通过下列反斜杠标识的方式在字符串模式中指定:\n:表示换行.\t:表示行制表符(tab)\f:表示换页\w:表示列制表符\r:表示回车说到这里,又不得不再次提及Windows 和 Linux/UNIX 对换行符识别的差别,Linux/UNIX下指定"\n"即可,Windows下需要指定"\r\n"才表示一个完整的换行符.X'hex_string':二进制字符,对于一些不可见字符,如像回车换行这类字符,可以将其转换成十六进制,然后再通过str X'hex_str'方式指定.

比如上述控制文件中的功能如果用二进制字符标识,形式如下:

iINFILE oracledata14.data "str X'7C0D0A'"

要查看指定字符的十六进制编码,可以通过UTL_RAW.CAST_TO_RAW生成,例如:

SQL> SELECT UTL_RAW.CAST_TO_RAW('|'||chr(13)||chr(10)) from dual;UTL_RAW.CAST_TO_RAW('|'||CHR(13)||CHR(10))
-------------------------------------------------------------------------------7C0D0A

要导入大字段(LOB类型)怎么办

LOB作为打字段数据类型,是Oracle新增的数据类型,用来替代long和long raw类型,一般SQLLDR操作中不会涉及大字段类型的操作.

1.数据保存在数据文件中.

这种方式可以按照5.3.10节中提到的方式处理,举个例子:

还是以MANAGER表为例,修改表中的REMARK列为LOB类型,在SQL*Plus命令环境中如下:

SQL> ALTER TABLE MANAGER DROP COLUMN REMARK; Table altered.SQL> ALTER TABLE MANAGER ADD REMARK CLOB;Table altered.

数据文件如下:

10,SMITH,SALES MANAGER,This is SMITH.
He is a Sales Manager.|
11,ALLEN.W,TECH MANAGER,This is ALLEN.W.
He is a Tech Manager.|
16,BLAKE,HR MANAGER,"This is BLAKE. He is a Hr Manager. The jobs responsibilities are in the following:
1.  Ensure the effective local implementation of corporate level HR initiatives and new programs.
2.  Take initiatives in defining HR strategy on attracting, hiring, integrating, developing, managing
3.  Oversee standard recruiting and procedures to ensure the company¡¯s staffing requirements are met in a timely manne
4.  Provide employees with fair and appropriate compensation and benefit, to ensure market competitiveness.
5.  Develop, implement and oversee the training and development programs to upgrade the skills of the  future challenges."|

示例代码保存为数据文件: oracledatat14.data

创建控制文件如下:

LOAD DATAINFILE oracledata14.data "str '|\n'"TRUNCATE INTO TABLE MANAGERFIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"'(MGRNO,MNAME,JOB,REMARK char(100000))BEGINDATA

控制文件保存为: ldr_case16.ctl

注意这里REMARK显式指定char(100000),因为Oracle默认所有输入字段都是char(255),如不显式指定类型和长度,一旦加载列的实际长度超出255,则数据加载就会报错:Field in data file exceeds maximum length.

执行SQLLDR加载数据.

数据成功加载!这种方式最关键的地方是必须保证REMARK列定义的长度大于数据文件中文本块的大小.

2. 数据保存在独立的文件中

这种数据相对于第一种更加常见,相应处理也更简单一些(跳过了换行符的处理),SQLLDR中提供了LOBFILE关键字,直接支持加载文件到LOB类型中.

首先再SQL*Plus命令行环境中连接数据库,创建一个新表:


SQL> CREATE TABLE LOBTBL (FILEOWNER VARCHAR2(30),FILENAME VARCHAR2(200),FILESIZE NUMBER,FILEDATA CLOB,CREATE_DATE DATE);

表中共有5列,分别表示文件属主,文件名,文件大小,文件内容和文件创建时间.

创建数据文件,内容如下:

2009-03-17  09:43     154 JUNSANSI /home/oracle/ldr_case1.ctl
2009-03-17  09:44     189 JUNSANSI /home/oracle/ldr_case1.log
2009-03-17  09:44   2,369 JUNSANSI /home/oracle/ldr_case2.ctl
2009-03-16  16:50     173 JUNSANSI /home/oracle/ldr_case2.log
2009-03-16  16:49     204 JUNSANSI /home/oracle/ldr_case3.ctl
2009-03-16  16:50   1,498 JUNSANSI /home/oracle/ldr_case3.log
2009-03-16  17:41     145 JUNSANSI /home/oracle/ldr_case4.ctl
2009-03-16  17:44     130 JUNSANSI /home/oracle/ldr_case4.log
2009-03-16  17:44   1,743 JUNSANSI /home/oracle/ldr_case5.ctl
2009-03-17  11:01     132 JUNSANSI /home/oracle/ldr_case5.log
2009-03-17  11:02     188 JUNSANSI /home/oracle/ldr_case6.ctl
2009-03-17  11:02   1,730 JUNSANSI /home/oracle/ldr_case6.log

示例代码保存为数据文件: oracledata15.data

创建控制文件如下:


LOAD DATA
INFILE oracledata15.data
TRUNCATE INTO TABLE LOBTBL
(
CREATE_DATE position(1:17) date 'yyyy-mm-dd hh24:mi',
FILESIZE position(*+1:24) "to_number(:FILESIZE,'99,999,999')",
FILEOWNER position(*+1:34),
FILENAME position(*+1) char(200) "substr(:FILENAME,instr(:FILENAME,'\\',-1)+1)",
FILEDATA LOBFILE(FILENAME) TERMINATED BY EOF )
BEGINDATA

示例文件保存为控制文件:ldr_case17.ctl

这个控制文件是之前介绍示例应用的集大成者,又有定长处理,又有函数转换,唯一陌生的就是最后一行:LOBFILE就是前面提到的(FILENAME) TERMINATED BY EOF 这LOBFILE关键字,只需要指定FILENAME列,其他都是固定格式,调用时直接按此指定即可.

某些字段无值导致加载报错怎么办

比如你某天拿到了一个这样的一个数据文件:


SMITH,CLEAK,3904
ALLEN,SALESMAN,
WARD,SALESMAN,3128
KING,PRESIDENT,2523

示例代码『未实际保存』.[ora.data]

首先按照前面的例子去处理这些数据:


LOAD DATA
INFILE ora.data
TRUNCATE INTO TABLE BONUS
FIELDS TERMINATED BY ","
(ENAME,JOB,SAL)
BEGINDATA

控制文件『未实际保存』.[ora.ctl]

执行后报错,错误如下:


Record 2 : Rejected - Error on table BONUS, column SQL.
Column not found before end of logical record (use TRAILING NULLCOLS)

就本例的错误信息来说,SQLLDR提示已经非常清楚:直到行结束也没发现适当的列值.

这是本例中数据文件的第二行没有提供适当的值(这一点都不稀奇,不管数据量庞大与否,DBA绝对不能期望数据文件完全满足要求,因此在编写控制文件时,也要考虑到对意外情况的处理.)

针对这一错误,SQLLDR甚至连解决方案也一并提供:使用TRAILING NULLCOLS.TRAILING NULLCOLS的作用是当某行没有对应的列值时,SQLLDR就会自动将其赋为NULL,而不是报错.


SMITH,CLEAK,3904
ALLEN,SALESMAN,
WARD,SALESMAN,3128
KING,PRESIDENT,2523

数据文件保存: oracledata16.data

控制文件如下:


LOAD DATA
INFILE oracledata16.data
TRUNCATE INTO TABLE BONUS
FIELDS TERMINATED BY "," TRAILING NULLCOLS
//TRAILING NULLCOLS的作用是当某行没有对应的列值时,SQLLDR就会自动将其赋为NULL,而不是报错.
(ENAME,JOB,SAL)
BEGINDATA

通过这个示例,我们能够得到三点体会:

  1. 执行完操作后一定要验证,就本例来说,从SQLLDR命令的执行看起来一切征程,如果不是到SQL*Plus环境中查看导入的数据,恐怕都不知道有记录未被成功导入.
  2. 一定要注意看日志,SQLLDR虽然算不上智能,但是也不傻,有时候造成错误的原因只是它不知到怎么办好,不过日志文件中一定会留下处理痕迹,不管SQLLDR命令执行是否成功,日志文件总是能告诉我们其执行的更多细节.
  3. 以上全部都是.

100万条记录的数据加载

生成百万级的数据文件

连接到本地数据库(自己安装的):

找一个合适大小的表:

SELECT COUNT(0) FROM DBA_OBJECTS;
COUNT(0)----------65389

然后找一个有20行记录的表,对其进行笛卡尔运算,即可生成130万条记录了.

为了更好地体现通用性,我们在输出时对created日期做一下格式转换:


select a.owner||',"'||a.object_name||'",'||a.object_id||','||to_char(a.created,'yyyy-mm-dd hh24:mi:ss')||','||a.statusfrom dba_objects a,(select rownum rn from dual content by rownum<=20) b ;

示例代码保存为SQL文件:getobject.sql

set echo off
set term off
set line 1000 pages 0
set feedback off
set heading off
spool [当前路径]/ldr_object.csv
@[当前路径]/getobject.sql
spool off
set heading on
set feedback on
set term on
set echo on

示例代码保存为:SQL文件:call.sql

然后在SQL*Plus命令行环境中,执行下列命令即可:

SQL> @[当前路径]call.sql

然后就耐心等待把,132万的记录量,输出也是需要一定时间的.

查看:


exit
du -m ldr_object.csv//输出的数据以M为单位.

初始化环境

创建表:

CREATE TABLE OBJECTS(OWNER VARCHAR2(30),OBJECT_NAME VARCHAR2(50),OBJECT_ID NUMBER,STATUS VARCHAR2(2000),CREATED DATE);

创建Index.


create index idx_obj_owner_name on objects(owner,object_name);

执行导入

创建控制文件如下:


LOAD DATA
INFILE ldr_object.csv
INSERT INTO TABLE OBJECTS
FIELDS TERMINATED BY "," OPTIONALLY ENCLOSED BY '"'
(owner,
object_name ,
object_id,
created date 'yyyy-mm-dd hh24:mi:ss',
status char(2000)
)
BEGINDATA

控制文件保存为:ldr_object.ctl

这里注意,对于CREATED列,我们指定了日期格式,并进行了转换,这个格式一定要与数据文件中日期格式相符,不然日期格式转换时会报错并导致数据加载失败.

按照默认参数执行SQLLDR,看看需要多长时间,同时指定ERRORS参数值为10,明确指定出现10次错误即中止加载:


sqlldr SCOTT/TIGER CONTROL=ldr_object.ctl ERRORS=10

5.4.4 能不能再快一点呢

SQLLDR常规路径导入时默认一次加载64行,现在要加载的总行数已经达到百万级,十位数显然太小,我们首先尝试修改该值,先直接在后面加个0好了,看看能对效率起到多大的提升:

执行如下命令:sqlldr SCOTT/TIGER CONTROL=ldr_object.ctl ERRORS=10 ROWS=640

日志节选信息:


value used for ROWS parameter changed from 640 to 84
Table OBJECTS:1307820 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.Space allocated for bind array:        254856 bytes(84 rows)Read   buffer bytes: 1048576Total logical records skipped: 0Total logical records read:       1307820Total logical records rejected:0Total logical records discarded:        0Run began on Wed Jun 05 14:18:43 2013Run ended on Wed Jun 05 14:28:56 2013Elapsed time was:     00:10:12.39CPU time was:00:00:16.40

注意节选信息的第一行,该信息是提示由于640行所占用的空间已经超过了参数BINDSIZE的默认值,因此自动修改到最大可承受的84行,这说明BINDSIZE参数默认值偏小.速度只比刚才小了2秒(变化几乎可以忽略)

再进一步调整BINDSIZE参数值,默认为256k,我们将其修改为10M(1024kb * 1024 * 10 = 10485760),同时将一次加载的行数提高到5000.


sqlldr SCOTT/TIGER CONTROL=ldr_object.ctl ERRORS=10 ROWS=5000 BINDSIZE=10485760

时间变得更长,正在研究:

大约时间是:13:48

能不能再快一点呢

所有参数默认,只打开直接路径加载:


sqlldr SCOTT/TIGER CONTROL=ldr_object.ctl DIRECT=TRUE

靠,这个速度才是王道啊!


Table OBJECTS:1307820 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.Date conversion cache disabled due to overflow (default size: 1000)Bind array size not used in direct path.Column array  rows :    5000Stream buffer bytes:  256000Read   buffer bytes: 1048576Total logical records skipped: 0Total logical records read:       1307820Total logical records rejected:0Total logical records discarded:        0Total stream buffers loaded by SQL*Loader main thread:     1250Total stream buffers loaded by SQL*Loader load thread:     4996Run began on Wed Jun 05 14:55:12 2013Run ended on Wed Jun 05 14:56:28 2013Elapsed time was:     00:01:15.74CPU time was:00:00:11.80

有没有可能更快呢

这究竟是希望还是欲望,已经说不清楚了,反正没个尽头。

直接导入路径导入可用的参数也有不少,不过我们这里总数据量不大,因此实际能够起到效率提升的不多,我准备主要从以下两个参数入手:

  1. STREAMSIZE : 直接路径加载默认读取全部记录,因此不需要设置ROWS参数,读取到的数据处理后存入流缓存区,即STREAMSIZE参数,该参数默认值为256kb,这里加大到10MB.
  2. DATE_CACHE : 该参数指定一个转换后日期格式的缓存区,以条为单位,默认值1000条,即保存1000条转换后的日期格式,由于我们要导入的数据中有日期列,因此加载该参数值到5000,以降低日期转换带来的开销.

修改参数后执行命令最终形式如下所示:


sqlldr SCOTT/TIGER CONTROL=ldr_object.ctl DIRECT=TRUE STREAMSIZE=10485760 DATE_CACHE=5000

可能已经达到性能瓶颈:

Date cache:Max Size:      5000Entries :      1207Hits    :   1306613Misses  :0Bind array size not used in direct path.Column array  rows :    5000Stream buffer bytes:16777216Read   buffer bytes: 1048576Total logical records skipped: 0Total logical records read:       1307820Total logical records rejected:0Total logical records discarded:        0Total stream buffers loaded by SQL*Loader main thread:     1250Total stream buffers loaded by SQL*Loader load thread:        0Run began on Wed Jun 05 15:15:39 2013Run ended on Wed Jun 05 15:17:07 2013Elapsed time was:     00:01:28.14CPU time was:00:00:09.05

SQL*Loader加载综述

事实上想在Oracle存储过程中调用SQLLDR非常麻烦,因为SQLLDR是一个执行程序而不是一个接口,在9i之前版本要在存储过程中实现类似功能也很复杂,虽然可以通过UTL_FILE之类的包间接实现,但需要编写大量脚本,考虑字符截取,过滤,判断等诸多事宜。

一个不慎就可能造成执行报错,或者更不慎,执行到一般的时候报错(可能比没执行还要麻烦),幸运的是,9i及之后的版本,Oracle提供了一个新的功能---外部表(External Tables),顾名思义就是数据存储在数据库之外的表,这是一个号称"SQL*Loader替代者"的新特性.

2013/06/05 15:25:57

--EOF--

https://www.bckf.cn/custom/sqlloader.html#5_2

SQL*Loader总结sqlldr相关推荐

  1. oracle数据库sqlloader,sql loader ---ORACLE SQLLDR

    sql loader的基本使用: 1. sql loader里有几个概念: 控制文件:和数据库的文件不是一回事,个人理解是用于数据加载控制的. 数据文件:要加载入库的数据文件,支持文本,csv, 等格 ...

  2. SQL Loader使用方法

    分享一下我老师大神的人工智能教程.零基础!通俗易懂!风趣幽默!还带黄段子!希望你也加入到我们人工智能的队伍中来!https://blog.csdn.net/jiangjunshow --======= ...

  3. java sqlldr导入_使用SQL*LOADER将TXT或CSV数据导入ORACLE(转)

    一.简介 SQL*LOADER是ORACLE的数据加载工具,通常用来将操作系统文件迁移到ORACLE数据库中.SQL*LOADER是大型数据仓库选择使用的加载方法,因为它提供了最快速的途径(DIREC ...

  4. sql loader导出数据和导入数据(sqlldr)

    一般我我们对表进行数据迁移的时候会用以下几种方法: 1. A表记录利用toad或者pl/sql工具将其导出为一条条分号隔开的insert语句,然后再执行插入到B表中 2.建立数据库间的dblink,然 ...

  5. oracle sqlload速度加快,oracle,sql loader 及 快速生成大量数据 CSV文件sqlldr

    要测试sql loader 以及快速产生大量测试数据 生成大量测试数据思路. 一,用plsql developer 生成csv 文件 二,用>>输出重定向,追加到一个cvs 文件里. 三, ...

  6. Oracle SQL Loader的详细语法

    Oracle   SQL   Loader的详细语法 SQL*LOADER是ORACLE的数据加载工具,通常用来将操作系统文件迁移到ORACLE数据库中.SQL*LOADER是大型数据 仓库选择使用的 ...

  7. linux oracle path恢复,Linux 环境下Oracle安装与调试(七)之SQL Loader,备份和恢复

    1.SQL Loader sql loader其实就是 把数据文件的数据插入到oracle数据表中. sql*loader 使用格式如下: sqlldr userid control data 也就是 ...

  8. sql loader 导入数据时的问题

    2019独角兽企业重金招聘Python工程师标准>>> 在使用oracle sql loader 工具导入数据时遇到的问题,具体的shell脚本如下: #!/bin/bashexpo ...

  9. SQL Loader 的使用详解

    Oracle 的SQL*LOADER可以将外部数据加载到数据库表中.下面是SQL*LOADER的基本特点: 1)能装入不同数据类型文件及多个数据文件的数据 2)可装入固定格式,自由定界以及可度长格式的 ...

最新文章

  1. 英特尔内存革新助平安云 Redis 云服务降本增效
  2. 【基础巩固篇】Java 8中对CAS的优化
  3. FILE文件流的中fopen、fread、fseek、fclose的使用
  4. C\S B\S 结果,其实就是这个样子的。
  5. SAP的模块化服务应用市场Hybris,前景如何?
  6. R学习_multitaper包解析1:子函数centre,dpss
  7. 16.IDA-列出函数中存在的全部call
  8. 把Python函数转换成能在SQL语句中调用的函数
  9. 1.3—Spring基础配置—3.AOP
  10. oracle时间类型
  11. FPGA基础入门篇(四) 边沿检测电路
  12. 自己做量化交易软件(37)小白量化实战10--操作方法与MetaTrader5高频策略的进化
  13. catia二次开发:IDE界面介绍
  14. linux css压缩工具下载,推荐15个最好用的JavaScript代码压缩工具
  15. 淘宝模板开发系列之DOM、CSS规范
  16. Java解析excel工具easyexcel 助你快速简单避免OOM
  17. java操作excel方法_Java实现操作excel表格的方法
  18. 认识linux内核结构
  19. redis中使用lua脚本
  20. Orcal ETL 增量抽取--ORA_ROWSCN伪列

热门文章

  1. 企业网站如何进行外链建设
  2. Ubuntu 搭建SVN服务器
  3. HTTP基本使用方法
  4. 51单片机-定时器中断
  5. 怎么注册公司邮箱?公司邮箱注册流程介绍
  6. Linux性能分析工具详解
  7. wx.showModal(模态框)的相关设置
  8. 全链路压测核心技术解析
  9. Ubuntu 命令大全 Ubuntu技巧 (转)
  10. NodeJS C++ Addons之C++类实例包装与异步操作