我必须在我的数据库上加载数百万条记录,表示记录需要根据它们的一些列值进一步处理。特别是如果一行满足条件,我将该行保存在表B中,否则我将其保存在表C中。
根据文档,带有DIRECT PATH的sqlldr非常快,无论如何加载这样的行都不会触发触发器。所以,我想出了两个解决方案:
解决方案1:
使用带有DIRECT PATH = true的sql loader来加载表A中的所有数据。然后调用存储过程来执行实际过滤。我不太确定,但在这种情况下,oracle实际上会在幕后执行多线程。
解决方案2:
使用带有DIRECT PATH = false的sql loader并在表A上插入后激活触发器。在这种情况下,为了性能,我需要通过在多个文件中分割我的数据文件并多次调用sql loader来显式执行多线程(顺便说一句,我不知道如何在bash脚本上做到这一点......)
哪一个会带来更好的表现?两者之间的性能差异是多少?
答案 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,COMPLETED)之类的东西来控制流程,您可以灵活且易于管理。我做的最后一个项目,我们从文件中加载了数百万行,然后在安静的批处理期间分批处理它们几个晚上。
明智地编码它可能更多的工作,但是弄乱文件和坏记录并通过sqlldr重新加载和避免重复比表数据更麻烦。