Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/oracle/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Oracle 数据过滤性能:sqlldr+触发器还是sqlldr+存储过程?_Oracle_Sql Loader - Fatal编程技术网

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

Oracle 数据过滤性能:sqlldr+触发器还是sqlldr+存储过程?,oracle,sql-loader,Oracle,Sql Loader,我必须在我的数据库中加载数百万条记录,这些记录需要根据它们的某些列值进行进一步处理。特别是,如果一行满足一个条件,我将该行保存在表B中,否则我将其保存在表C中 根据文档,使用直接路径的sqlldr非常快,无论如何,加载这样的行不会触发触发器。因此,我提出了两个解决方案: 解决方案1: 使用直接路径为true的sql loader加载表A中的所有数据。然后调用存储过程执行实际筛选。我对此不太确定,但在本例中,oracle似乎在幕后执行多线程处理 解决方案2: 使用sql loader with D

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

根据文档,使用直接路径的sqlldr非常快,无论如何,加载这样的行不会触发触发器。因此,我提出了两个解决方案:

解决方案1:

使用直接路径为true的sql loader加载表A中的所有数据。然后调用存储过程执行实际筛选。我对此不太确定,但在本例中,oracle似乎在幕后执行多线程处理

解决方案2:

使用sql loader with DIRECT PATH=false并在表A上插入后激活触发器。在这种情况下,为了性能起见,我需要将数据文件拆分为多个文件并多次调用sql loader来明确执行多线程处理,我不知道如何在bash脚本上执行该操作


哪一种会带来更好的性能?两者之间的性能差异有多大?

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

编辑

我自己从来没有写过多表插入,所以我想我应该试试。它很整洁

  > 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               

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

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


从编码角度看,这可能需要更多的工作,但通过sqlldr处理文件和坏记录、重新加载和避免重复比作为表数据更麻烦。

我不太喜欢pl/sql,但是否可以在insert all语句之后立即为每个循环插入一个?显然,我不想手动编写数百万个插入:我添加了一个示例。您应该很好地回答一点OT:直接路径禁用索引和自动增量触发器。。。我确实有索引和一个不可为空的ID列。如何处理这个问题?正如我所说的,将它加载到一个暂存区域,这些可以是没有索引/约束的新表,然后处理到主数据表中。您可以禁用索引,然后重新生成它们,但这是一种平衡行为,具体取决于在处理过程中是否必须从禁用的索引表中读取。正如daivrz所说,我们所能做的就是提供一般性的建议,你所决定的实际过程取决于你的实验。