数据过滤performance:sqlldr+触发器还是sqlldr+存储过程?

Data filtering performance:sqlldr+triggers or sqlldr+stored procedure?

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

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

解决方案 1:

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

解决方案 2:

使用带 DIRECT PATH=false 的 sql 加载程序,在 table A.in 上插入后激活触发器,在这种情况下,为了性能起见,我需要通过拆分我的多个文件中的数据文件并多次调用 sql 加载程序(顺便说一句,我不知道如何在 bash 脚本上执行此操作...)

哪一个性能更好?两者之间有那么大的性能差异吗?

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

编辑

我从来没有真正写过一个多 table 插入自己所以我想我会尝试。挺好看的。

  > 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               

在加载数据然后需要 processing/cleansing 添加到核心数据的情况下,我的强烈偏好是先将其加载到分段 table,并使用最快的可用方法,即 sqlldr直接路径。这样可以快速完成数据加载和清理。直接路径对日志记录和恢复有影响,因此最好将 activity 保持在尽可能小的 window 范围内。

然后可以使用存储过程更灵活地处理暂存数据。在这里,您可以将记录分成批次,并让存储过程通过参数处理特定的批次,然后在离散批次上并行处理超过 1 个存储过程 运行(假设每个记录都可以离散处理)。添加诸如流程状态(就绪、正在检查、失败、已完成)之类的内容来控制流程,您就拥有了一些灵活且更易于管理的东西。在我做的最后一个项目中,我们从文件中加载了 1 亿行,然后在安静的批处理期间用几个晚上的时间分批处理它们。

明智的编码可能需要更多工作,但通过 sqlldr 处理文件和错误记录并重新加载和避免重复比 table 数据更麻烦。