Oracle百万级数据导入(sqlldr)

您所在的位置:网站首页 sqlldr导入大量文件的数据慢 Oracle百万级数据导入(sqlldr)

Oracle百万级数据导入(sqlldr)

2024-01-12 22:23| 来源: 网络整理| 查看: 265

前言:刚过完元旦,2019年的第一个任务,是在生产环境将一份配置数据从数据库A迁移到数据B(200多万条记录),数据库B为多个生产系统公用数据库,已效力多年,并且长期处于放养状态,如今早已年弱体衰,反应迟钝。将数据拿到手上后,先弄了1万条记录试下了水,发现不管是通过直接执行INSERT语句还是通过文本导入器,要把这200多万条记录都是我无法承受的痛。无奈之下,只能在网上另寻他法,这才发现原来有此等神器:sqlldr

什么是sqlldr

sqlldr是Oracle内置的工具,用来快速导入大批量数据,直接在命令行调用。

sqlldr参数

下表是sqlldr的部分参数,其中加粗的为常用参数,标红为必需参数。 注:sqlldr的命令行参数可以直接写在命令行,也可以放在控制文件,也可以直接放在参数文件PARFILE里面(在参数重复指定时,命令行中的参数具有最高的权重)

属性值含义默认值useridOracle的username/password[@servicename]control控制文件log日志文件默认与控制文件同名bad坏数据文件默认与数据文件同名discard丢弃的数据文件discardmax允许丢弃数据的最大值全部skip跳过的行/记录数,比如导入的数据文件前几行是表头或者描述0load加载的行/记录数全部errors允许的错误行/记录数50rows每次提交的记录数,该参数受bindsize影响常规路径:64 直接路径:全部bindsize每次提交记录的缓冲区的大小(字节)256000silent禁止输出信息(header,feedback,errors,discards,partitions)parfile参数文件:包含参数规范的文件名direct使用直通路径方式导入,不走buffer cache,通过direct path api发送数据到服务器端的加载引擎,加载引擎按照数据块的格式处理数据并直接写向数据文件,因此效率较高falseparallel并行导入,仅在直接路径加载时有效,推荐设置truefalsefile并行加载时会用到该参数,指定file参数,要加载的内容即只向指定的数据文件写入数据,减少i/oskip_unusable_indexes不允许/允许不可用的索引或索引分区falseskip_index_maintenance不维护索引,将受影响的索引标记为不可用falsecommit_discontinued停止加载时提交加载的行falsereadsize缓冲区大小(字节)1048576,最大不超过20m,该参数仅当从数据文件读取时有效,如果是从近制文件读取数据,则默认为64kexternal_table使用外部表进行加载不使用generate_onlysqlldr并不执行加载,而是生成创建外部表的sql和处理数据的sql,并保存在log文件中execute执行外部表并加载数据columnarrayrows指定直接路径加载时流缓冲区的行数5000streamsize指定直接路径加载时流缓冲区的大小(字节)256000multithreading指定直接路径加载时是否启用多线程date_cache指定直接路径加载时日期转换用缓存大小(以条目为单位)1000no_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", ) 执行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

执行完后,结果将会保存至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';

若不一致,则将控制文件里的characterset参数改为与导出服务端字符集一致即可 characterset ‘ZHS16GBK’



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3