Oracle大数据的导入与更新方案

近来有好一段时间停笔了,原因是年前刚跳槽,然后新公司刚入手,没有时间,实在太忙,烦请各位读者见谅。

上周的工作中,接到一个任务,是处理一个上百万数据量的数据处理任务,需要把一个上百万数据量的csv文件内容,导入到oracle中的临时表中,然后根据临时表更新业务表中的一些状态字段,如果单独用关联更新的方法,会非常的耗时。经过网上的一些资料检索,以及公司DBA的支持,得出以下方案。

1. oracle 大数据量加载方法汇总

1.1 常用方法

在 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.2 Oracle的Sql Loader (sqlldr) 的用法

在命令行下执行 Oracle 的 sqlldr 命令,可以看到它的详细参数说明,要着重关注以下几个参数:

userid -- Oracle 的 username/password[@servicename]
control -- 控制文件,可能包含表的数据
-------------------------------------------------------------------------------------------------------
log -- 记录导入时的日志文件,默认为 控制文件(去除扩展名).log
bad -- 坏数据文件,默认为 控制文件(去除扩展名).bad
data -- 数据文件,一般在控制文件中指定。用参数控制文件中不指定数据文件更适于自动操作
errors -- 允许的错误记录数,可以用他来控制一条记录都不能错
rows -- 多少条记录提交一次,默认为 64
skip -- 跳过的行数,比如导出的数据文件前面几行是表头或其他描述

还有更多的 sqlldr 的参数说明请参考:sql loader的用法

1.3 sql Loader示例

具体sql loader的示例代码在github上的sqlloader目录下。
执行命令:sqlldr dbuser/dbpass@dbservice control=update_data.ctl

注意:sqlldr为系统命令,在pl/sql下是不能执行的,需要在操作系统中执行(linux下),sql plus不知道行不行。

参考链接: https://www.cnblogs.com/flish/archive/2010/05/31/1748221.html

2.Oracle大数据量更新方法

第一节介绍了大数据量的导入方法,这边介绍一下,大数据量如何批量更新的问题。

2.1 关联更新

UPDATE (SELECT \*+ BYPASS_UJVC *\
         T1.SEND_EMAIL, T3.EMAIL_STATUS_USER
          FROM USER_PROFILE                      T1,
              EMAIL_APP_LEAD    T2,
              EMAIL_FLAG_STATUS T3
         WHERE T1.USER_PROFILE_ID = T2.USER_PROFILE_ID
           AND T2.EMAIL_FLAG = T3.EMAIL_FLAG
           AND T2.USER_PROFILE_ID IS NOT NULL) R
   SET R.SEND_EMAIL = R.EMAIL_STATUS_USER;

此种方法耗时比较久,并且使用这种方式来更新表,需要用于更新的表(最终数据表)的关联字段必须设置为主键,且不可多字段主键。

2.2 加入并行度,hash,并且加入rowid排序

DECLARE
  MAX_ROWS NUMBER DEFAULT 10000;

  --APP
  ROW_ID_TABLE_APP     DBMS_SQL.UROWID_TABLE;
  EMAIL_FLAG_TABLE_APP DBMS_SQL.VARCHAR2_TABLE;
  -- APP CURSOR
  CURSOR EMAIL_APP_CUR IS
    SELECT /*+ use_hash(t1,t2) parallel(t1,4) parallel(t2,4) */
     T3.EMAIL_STATUS_USER, T1.ROWID
      FROM USER_PROFILE                      T1,
           EMAIL_APP_LEAD    T2,
           EMAIL_FLAG_STATUS T3
     WHERE T1.USER_PROFILE_ID = T2.USER_PROFILE_ID
       AND T2.EMAIL_FLAG = T3.EMAIL_FLAG
       AND T2.USER_PROFILE_ID IS NOT NULL
     ORDER BY T1.ROWID;
BEGIN
  DBMS_APPLICATION_INFO.SET_MODULE('EHI_APP', '');
  --UPDATE USER_PROFILE FROM APP
  OPEN EMAIL_APP_CUR;
  LOOP
    EXIT WHEN EMAIL_APP_CUR%NOTFOUND;
    FETCH EMAIL_APP_CUR BULK COLLECT
      INTO EMAIL_FLAG_TABLE_APP, ROW_ID_TABLE_APP LIMIT MAX_ROWS;
    FORALL I IN 1 .. ROW_ID_TABLE_APP.COUNT
      UPDATE USER_PROFILE
         SET SEND_EMAIL = EMAIL_FLAG_TABLE_APP(I),UPDATED_BY = 'BKOF-7959-Webbula',UPDATED_WHEN=SYSDATE
       WHERE ROWID = ROW_ID_TABLE_APP(I);
    COMMIT;
  END LOOP;

END;

具体代码示例参考目录github下的bigdata_update

2.3 参考链接

  1. http://blog.csdn.net/leinuo180/article/details/23344647
  2. http://blog.sina.com.cn/s/blog_69e9f7cd0100nm2t.html
    原文作者:landy8530
    原文地址: https://www.jianshu.com/p/0673edd8e40d
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞