数据过滤性能:sqlldr + triggers还是sqlldr +存储过程?

时间:2015-06-18 21:18:28

标签: oracle sql-loader

我必须在我的数据库上加载数百万条记录,表示记录需要根据它们的一些列值进一步处理。特别是如果一行满足条件,我将该行保存在表B中,否则我将其保存在表C中。

根据文档,带有DIRECT PATH的sqlldr非常快,无论如何加载这样的行都不会触发触发器。所以,我想出了两个解决方案:

解决方案1:

使用带有DIRECT PATH = true的sql loader来加载表A中的所有数据。然后调用存储过程来执行实际过滤。我不太确定,但在这种情况下,oracle实际上会在幕后执行多线程。

解决方案2:

使用带有DIRECT PATH = false的sql loader并在表A上插入后激活触发器。在这种情况下,为了性能,我需要通过在多个文件中分割我的数据文件并多次调用sql loader来显式执行多线程(顺便说一句,我不知道如何在bash脚本上做到这一点......)

哪一个会带来更好的表现?两者之间的性能差异是多少?

2 个答案:

答案 0 :(得分:1)

您了解绩效的唯一方法是实际尝试不同的方法。对于第一个选项,您可以尝试直接SQL,而不是使用过程(可能会导致逐行处理)。见multi table inserts。这允许您指定将插入指向不同表的条件。

修改

我自己从未真正写过多表插页,所以我想我会尝试。它非常整洁。

  > CREATE TABLE t_stg
  (pk NUMBER PRIMARY KEY
  ,cond NUMBER
  ,text VARCHAR2(20))

  table T_STG created.

  > CREATE TABLE t_1 AS SELECT * FROM t_stg WHERE 1=2

  table T_1 created.

  > CREATE TABLE t_2 AS SELECT * FROM t_stg where 1=2

  table T_2 created.

  > INSERT INTO t_stg
  (SELECT LEVEL lvl 
        ,mod(LEVEL, 2) cond
        ,to_char(SYSDATE + LEVEL, 'Day') txt
  FROM dual
  CONNECT BY LEVEL < 8)

  7 rows inserted.

  > SELECT *
  FROM   t_stg

          PK       COND TEXT               
  ---------- ---------- --------------------
           1          1 Sunday               
           2          0 Monday               
           3          1 Tuesday              
           4          0 Wednesday            
           5          1 Thursday             
           6          0 Friday               
           7          1 Saturday             

   7 rows selected 

  > INSERT ALL
  WHEN cond = 1 THEN
     INTO t_1 (pk, cond, text) VALUES (pk*2, cond, text)
  ELSE
     INTO t_2 (pk, cond, text) VALUES (pk, cond, text)
  SELECT pk
        ,cond
        ,text
  FROM   t_stg

  7 rows inserted.

  > SELECT *
  FROM   t_1
          PK       COND TEXT               
  ---------- ---------- --------------------
           2          1 Sunday               
           6          1 Tuesday              
          10          1 Thursday             
          14          1 Saturday             

  > SELECT *
  FROM   t_2

          PK       COND TEXT               
  ---------- ---------- --------------------
           2          0 Monday               
           4          0 Wednesday            
           6          0 Friday               

答案 1 :(得分:1)

在加载数据的情况下,在添加到核心数据之前需要处理/清理我的强烈偏好是首先将其加载到临时表中,并使用最快的可用方法,即具有直接路径的sqlldr。这样可以快速完成数据加载和灰尘。关于日志记录和恢复的直接路径存在影响,因此最好将该活动保持在尽可能小的窗口。

然后可以使用存储过程以更大的灵活性处理分段数据。在这里,您可以将记录拆分为批次,并使存储过程通过参数处理特定批次,然后在离散批次上并行运行多个存储过程(假设每个记录可以离散处理)。添加诸如流程状态(READY,CHECKING,FAILED,COM​​PLETED)之类的东西来控制流程,您可以灵活且易于管理。我做的最后一个项目,我们从文件中加载了数百万行,然后在安静的批处理期间分批处理它们几个晚上。

明智地编码它可能更多的工作,但是弄乱文件和坏记录并通过sqlldr重新加载和避免重复比表数据更麻烦。