SQL Loader,触发饱和度?

时间:2013-07-02 22:39:49

标签: performance oracle triggers sql-loader

我有一种情况我无法找到解释,这里是。 (我将使用假设信息,因为原始信息非常大。)

我有一张桌子,让我们说:

table_a
-------------
name
last name
dept
status
notes

此表在插入时有一个触发器,它根据验证结果对信息进行了大量验证,以更改新记录的状态字段,其中一些验证是:

- check for the name existing in a dictionary
- check for the last name existing in a dictionary
- check that fields (name,last name,dept) aren't already inserted in table_b
- ... and so on

问题是,如果我通过查询在表上插入,比如

insert into table_a 
(name,last_name,dept,status,notes) 
values
('john','smith',1,0,'new');

只需173 ms即可完成所有验证过程,更新状态字段并在表中插入记录。 (验证过程通过索引完成所有搜索)

但是如果我通过SQLloader尝试这个,读取一个包含5000条记录的文件,则需要40分钟来验证并插入149条记录(当然我已将其杀死了......)

所以我尝试加载禁用触发器的数据(检查速度) 我知道它在不到10秒的时间内像所有记录一样加载。

所以我的问题是,我该怎么做才能改善这个过程?我唯一的理论是,我可以使数据库饱和,因为它加载速度很快,并启动了许多触发器实例,但我真的不知道。

我的目标是使用信息加载大约60个文件并通过触发器中的过程验证它们(尽管愿意尝试其他选项)。

我真的很感激你能提供的任何帮助!!

COMPLEMENT - -------------------------------------- ------------------------------------------

感谢您的回答,现在我将阅读所有相关内容,现在希望您能帮我解决这个问题。让我解释一下我需要的一些功能(我使用了触发器,因为我无法想到其他任何东西)

所以表数据附带了这个(重要的)字段:

pid name lastname birthdate dept cicle notes

数据就像这样

name lastname birthdate dept

现在,触发器对数据执行此操作:

  1. 调用函数来计算pid(使用算法根据名称,姓氏和出生日期计算)

  2. 调用一个函数来检查字典上的名字(因为在我的字典中我有单个名字,这意味着如果一个人被命名为john aaron smith jones,则函数将john aaron分成两部分,并搜索john和字典中的aaron在单独的查询中,这就是为什么我没有使用外键[以避免有很多组合john aaron,john alan,john pierce..etc])--->有点坚持如何实现这个没有更改字典的密钥...也许有一个CHECK ?,姓氏外键是个好主意。

  3. 根据dept和当前日期从另一个表中获取cicle(因为一个人可以在同一个部门的表中出现两次,但是在不同的cicle中)--->我怎么能得到这个cicle以更有效的方式进行正确的搜索?

  4. 最后,在完成所有这些验证之后,我需要确切地知道哪些验证未得到满足(因此字段说明),因此触发器连接所有失败验证的字符串,如下所示:

    lastname not in dictionary, cannot calculate pid (invalid date), name not in dictionary

  5. 我知道如果不满足约束检查,我所能做的就是将记录插入另一个带有约束失败错误消息的表中,但这只留下一次验证,我是对的吗?但我需要验证所有这些并将报告发送给其他部门,以便他们可以查看数据并对其进行所有必要的调整。

    无论如何,这是我现在的情况,我将探索各种可能性,并希望你能分享整个过程的一些亮点,非常感谢你的时间。

1 个答案:

答案 0 :(得分:3)

你已经解决了这个问题的一半:

  

“所以我尝试加载禁用触发器的数据(检查速度)......它在不到10秒的时间内像所有记录一样加载。”

这并不奇怪。您当前的实现为您插入表B的每一行执行了大量单行SELECT语句。这将不可避免地给您一个糟糕的性能配置文件。 SQL是一种基于集合的语言,在多行操作中表现更好。

所以,你需要做的是找到一种方法来替换所有更有效的替代方法的SELECT语句。然后,您将能够永久删除触发器。例如,使用表A列和引用表之间的外键替换字典上的查找。作为内部Oracle代码的关系完整性约束比我们编写的任何代码(并且也在多用户环境中工作)表现得更好。

如果表B中已存在列的组合,则不插入表A的规则更成问题。不是因为它很难做,而是因为它听起来像是糟糕的关系设计。如果您不希望在表A中已经退出表A时加载记录,为什么不直接加载到表B中?或者你有一个列的子集应该从表A 表B中提取出来并形成表C(它与A和B有外键关系)?

无论如何,将它留在一边,你可以通过用外部表替换SQL * Loader来实现基于set的SQL。外部表允许我们将CSV文件呈现给数据库,就像它是常规表一样。这意味着我们可以在普通的SQL语句中使用它。 Find out more.

因此,对于字典和外部表的外键约束,您可以使用此语句替换SQL Loader代码(取决于其他任何规则包含在“......等等”):

insert into table_a
select ext.* 
from external_table ext
     left outer join table_b b
     on (ext.name = b.name and ext.last_name = b.last_name and ext.dept=b.dept)
where b.name is null
log errors into err_table_a ('load_fail') ;

这采用DML错误日志记录语法以基于集合的方式捕获所有行的约束错误。 Find out more。它不会引发表B中已存在的行的异常。您可以使用the multi-table INSERT ALL将行路由到溢出表,或者在事件之后使用MINUS set操作来查找外部表中的行,这些行不是表A中的t取决于您的最终目标以及您需要如何报告事物。

也许是一个比你期望的更复杂的答案。 Oracle SQL是一种非常广泛的SQL实现,具有许多用于提高批量操作效率的功能。我们真的需要阅读概念指南和SQL参考资料,以了解我们可以用Oracle做多少工作。