什么是sqlldr
sqlldr是Oracle内置的工具,用来快速导入大批量数据,直接在命令行调用。
sqlldr参数
下表是sqlldr的部分参数,其中加粗的为常用参数,标红为必需参数。
注:sqlldr的命令行参数可以直接写在命令行,也可以放在控制文件,也可以直接放在参数文件PARFILE里面(在参数重复指定时,命令行中的参数具有最高的权重)
属性值 含义 默认值
userid Oracle的username/password[@servicename]
control 控制文件
log 日志文件 默认与控制文件同名
bad 坏数据文件 默认与数据文件同名
discard 丢弃的数据文件
discardmax 允许丢弃数据的最大值 全部
skip 跳过的行/记录数,比如导入的数据文件前几行是表头或者描述 0
load 加载的行/记录数 全部
errors 允许的错误行/记录数 50
rows 每次提交的记录数,该参数受bindsize影响 常规路径:64 直接路径:全部
bindsize 每次提交记录的缓冲区的大小(字节) 256000
silent 禁止输出信息(header,feedback,errors,discards,partitions)
parfile 参数文件:包含参数规范的文件名
direct 使用直通路径方式导入,不走buffer cache,通过direct path api发送数据到服务器端的加载引擎,加载引擎按照数据块的格式处理数据并直接写向数据文件,因此效率较高 false
parallel 并行导入,仅在直接路径加载时有效,推荐设置true false
file 并行加载时会用到该参数,指定file参数,要加载的内容即只向指定的数据文件写入数据,减少i/o
skip_unusable_indexes 不允许/允许不可用的索引或索引分区 false
skip_index_maintenance 不维护索引,将受影响的索引标记为不可用 false
commit_discontinued 停止加载时提交加载的行 false
readsize 缓冲区大小(字节) 1048576,最大不超过20m,该参数仅当从数据文件读取时有效,如果是从近制文件读取数据,则默认为64k
external_table 使用外部表进行加载 不使用
generate_only sqlldr并不执行加载,而是生成创建外部表的sql和处理数据的sql,并保存在log文件中
execute 执行外部表并加载数据
columnarrayrows 指定直接路径加载时流缓冲区的行数 5000
streamsize 指定直接路径加载时流缓冲区的大小(字节) 256000
multithreading 指定直接路径加载时是否启用多线程
date_cache 指定直接路径加载时日期转换用缓存大小(以条目为单位) 1000
no_index_errors 在任何索引错误上中止加载 false
sqlldr导入有两种模式,常规路径加载和直接路径加载,默认使用常规路径加载,当direct=y或者direct=true时,使用直接路径加载。直接路径加载比常规路径拥有更高的效率,但也有诸多限制。
常规路径加载
数据经过buffer cache,使用SQL处理数据,COMMIT提交操作,一次加载可能会涉及到多个事务处理,会产生大量undo数据(回滚数据)
通过undo回滚
触发INSERT 触发器
操作过程中表仍可被并发访问
直接路径加载
数据不经过buffer cache,从PGA直接把数据格式化成Oracle块,再写入数据文件,几乎不会产生undo数据。但是如果表上有索引,会产生索引的undo数据,而且索引的块会被读进buffer cache,这将会花费大量时间在索引的维护上。因此,在向表中传送大量数据时,建议先将表上的索引设置为unusable(或者使用skip_index_maintenance=true),待插入结束后,再rebuild索引 (alter index index_name rebuild nologging)
数据不会写入HWM(高水位线)以下的数据块,而是在HWM之后写入,通过HWM回滚
触发器在进行直接路径加载之前已禁用,在加载结束时会重新启用,如果重新启用时不能访问某个被引用对象,这些触发器可能会保持为禁用状态
操作过程中对应的表会将会被锁定,所有在这张表上的CRUD操作将会被禁止,不能并发访问
控制文件
控制文件为sqlldr的必需项,在这个文件里指定了数据源,编码,操作类型,要操作的表等一系列参数,控制文件常见设置如下:
--关闭归档日志,提高导入速度(仅直接路径时有效)
--unrecoverable
load data
--指定编码
characterset 'UTF8'
--1.指定要加载的数据文件
--INFILE 和INDDN是同义词,它们后面都是要加载的数据文件。如果用 * 则表示数据就在控制文件内。
[ { INFILE | INDDN } {file | * } ]
--BADFILE和BADDN是同义词。file指定坏数据保存的文件
[{ BADFILE | BADDN } file ]
--DISCARDFILE和DISCARDDN是同义词。file指定丢弃的数据文件
[{ DISCARDFILE | DISCARDDN } file ]
--2.指定操作类型
--insert:默认值,装载空表,如果原先的表有数据,sqlloader会停止
--append:原先的表有数据 就在表中追加新记录
--replace:删除旧记录(用 delete from table 语句),替换成新装载的记录
--truncate:删除旧记录(用 truncate table 语句),替换成新装载的记录
[ APPEND | REPLACE | INSERT | TRUNCATE ]
--3.指定操作的表
INTO TABLE [user.]table
--4.指定过滤条件
--[when id = id_memo]
--5.指定字段分隔符
--字段分隔符
fields terminated by ','
--字段用什么字符包括起来
optionally enclosed by '"'
--字段没有对应的值时允许为空
trailing nullcols
--6.指定表字段
--常见数据类型
--CHAR 字符
--DATE 日期
--INTEGER 整数
--FLOAT 普通符点
--DOUBLE 双精度符点
(
id,--类型未指定时,默认为character,每个字段的实际解析类型见log文件
code integer,
name char(1000),
sum double,
create_date date "yyyy-mm-dd hh24:mi:ss",
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
执行sqlldr
编写好控制文件test.ctl后,就可以通过命令行执行导入,由于我使用的数据源文件为PL/SQL直接导出的csv文件,因此要跳过第一行记录(表头),以下为windows下的使用示例:
//常规路径
//调整每次提交的行数和缓冲区大小,以减少事务提交的次数
sqlldr userid=xxx/xxxxxx@xxxxxx control=test.ctl log=test.log skip=1 rows=5000 bindsize=20971520 readsize=20971520
//直接路径
//开启parallel和unrecoverable(控制文件中)
sqlldr userid=xxx/xxxxxx@xxxxxx control=test.ctl log=test.log skip=1 direct=true parallel=true skip_index_maintenance=true readsize=20971520 columnarrayrows=10000 streamsize=20971520 date_cache=5000
1
2
3
4
5
6
7
执行完后,结果将会保存至test.log文件中(不管成功还是失败),经测试,200万数据,使用常规路径加载在有索引的情况下导入时间约为15分钟左右,使用直接路径加载导入时间约为4分钟左右。
常见问题及解决
1.数据文件的字段超出最大长度:
检查报错字段长度是否超过255,若超过255,需要在控制文件中指明字段长度,如:char(1000),否则Oracle会默认该字段为VARCHAR(255)/CHAR(255)
2. TERMINATED 和 ENCLOSED 字段后没有终止定界符:
1).检查数据源文件是否格式正确
2).检查报错字段的前一个字段是否为数字,如果该字段为数字,并且在控制文件中指定了数据类型,尝试将指定的数据类型删掉,使用默认的类型,避免转换时匹配不一致
3. ORA-01722: 无效数字:
检查报错字段在控制文件中是否指定了数据类型,尝试将指定的数据类型删掉,使用默认的类型,避免转换时匹配不一致
4.ORA-01438: 值大于为此列指定的允许精度:
检查数据库字段类型与控制文件中指定的字段类型是否一致
5.SQL*Loader-700: 执行重要的分配 [7] 时内存耗尽:
这个异常一般发生在直接路径加载时,如果表字段很多,或者每次向内存加载的行数过大时(columnarrayrows),sql*loader无法向系统申请到足够的内存空间,就会报出out of memory的错误。
检查执行的命令行里是否包含columnarrayrows参数,如果有,将该参数的值调小,如果没有,加入该参数并且设置值小于5000(5000为默认值)
6.sqlldr不是内部命令或外部命令:
sqlldr.exe在Oracle安装路径的BIN文件夹里,先检查是否安装Oracle,如果未安装,则需要安装Oracle;如果已安装,则检查环境变量PATH是否包含Oracle安装路径的BIN文件夹,如果没有,在Path后加上Oracle_Path\BIN
7.SQL*Loader-704: 内部错误: ulconnect: OCIServerAttach [0]
ORA-12154: TNS: 无法解析指定的连接标识符
检查命令行userid参数的值username/password[@servicename]是否正确
8.sqlldr导入中文乱码:
检查Oracle导出服务端与导入服务端字符集是否一致
select * from v$nls_parameters t where t.PARAMETER = 'NLS_CHARACTERSET';
1
若不一致,则将控制文件里的characterset参数改为与导出服务端字符集一致即可
characterset ‘ZHS16GBK’
————————————————
版权声明:本文为CSDN博主「RELAXXXXXXX」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/labixiaofeng/article/details/85698899