OracleBulkCopy专门做什么,如何优化其性能?


14

总结细节:我们需要将大约500万行转移到供应商(Oracle)数据库中。使用OracleBulkCopy(ODP.NET)批量处理50万行时一切都很好,但是当我们尝试扩展到5M时,一旦达到1M标记,性能就会开始缓慢爬行,随着更多行的加载,性能会逐渐变慢,最终3小时左右后超时。

我怀疑这是涉及到对表的主键,但我一直在用拖网捕信息的甲骨文论坛和堆栈溢出,很多东西我读的是相矛盾(也很多帖子似乎与对方) 。我希望有人能就与该流程密切相关的一些问题直接记录下来:

  1. 请问OracleBulkCopy类使用常规或直接路径加载?有什么方法可以确认这一点吗?

  2. 假设它确实使用直接路径加载:Oracle是否在加载期间自动将所有索引设置为不可用,然后将它们重新设置为联机,这是真的吗?我已经阅读了几篇有关此问题的声明,但同样无法确认。

  3. 如果#2是true,那么在启动批量复制操作之前,表上的索引应该有什么区别吗?如果是这样,为什么?

  4. 与#3相关,通常,在具有无法使用的索引的批量加载与在加载之前实际删除索引并在之后重新创建索引之间,是否有实际的区别?

  5. 如果#2 正确,或者有一些我不了解的警告,那么在大容量加载之前显式使索引不可用,然后在之后显式重建索引 是否有任何区别?

  6. 除了索引构建以外,还有其他什么可能会导致随着添加越来越多的记录,批量复制操作的速度逐渐变慢?(也许与日志记录有关,尽管我希望不记录批量操作?)

  7. 如果除了先删除PK /索引外,实际上没有其他方法可以使性能降低,我可以采取哪些步骤来确保索引不会完全消失,即,如果与数据库的连接丢失了,过程的中间?


旁注:正在复制的数据已经按照PK(表中的唯一索引)进行了排序。
亚伦诺特,2011年

您是否正在使用DataReader从源读取数据?
bernd_k 2011年

@bernd_k:不,完全从内存加载。绝对不是问题所在。
亚伦诺特,2011年

Answers:


13

经过几天的阅读和实验,我能够(大部分)回答很多这样的问题:

  1. 我发现这个埋在ODP.NET文档(具有讽刺意味的不是OracleBulkCopy文档):

    ODP.NET批量复制功能使用直接路径加载方法,该方法与Oracle SQL * Loader类似但不相同。使用直接路径加载比常规加载(使用常规SQL INSERT语句)要快。

    因此看来它确实使用直接路径。

  2. 我可以通过执行大量批量复制操作并从SQL Developer获取索引属性来进行验证。该指数没有出现UNUSABLE,而批量复制正在进行中。 但是,我还发现,OracleBulkCopy.WriteToServer如果索引以某种状态开始,它将拒绝运行UNUSABLE,因此很显然这里还有更多的事情发生,因为如果禁用和重建索引那样简单,那么它就不必关心初始状态。

  3. 它确实有差别特别,如果该指数也是一个制约因素。在上面链接的文档中找到了这个小宝石:

    启用的约束
    在Oracle批量复制期间,默认情况下会自动启用以下约束:

    • NOT NULL
    • UNIQUE
    • PRIMARY KEY (非空列上的唯一约束)

    NOT NULL约束在列数组构建时检查。违反NOT NULL约束的任何行都将被拒绝。

    UNIQUE在加载结束时重建索引时,将验证约束。如果索引违反UNIQUE约束,则该索引将保持“索引不可用”状态。

    该文档对加载过程中发生的事情有些模糊,尤其是在使用主键的情况下,但是绝对可以肯定的是- 使用主键与使用主键的行为不同。既然这样OracleBulkCopy会很高兴地使您违反索引约束(并在完成索引后将其插入UNUSABLE状态),我的直觉是它在批量复制期间建立了PK索引,但直到之后才对其进行验证

  4. 我不确定观察到的差异是在Oracle本身内部还是仅仅是怪癖OracleBulkCopy。陪审团对此仍未作出决定。

  5. OracleBulkCopy如果索引最初处于UNUSABLE状态,将抛出异常,因此这确实是一个有争议的问题。

  6. 如果其他因素,指标(尤其是PK指数)仍然是最重要的,因为我发现是:

  7. 使用相同的架构创建全局临时表(使用CREATE AS),然后将其批量复制到临时表中,最后INSERT将临时表从普通表复制到实际表中。由于临时表没有索引,因此大容量复制非常快,而最终复制INSERT也很快,因为数据已经在表中(我还没有尝试附加提示,因为5M行表到表的副本已经花费了不到1分钟的时间)。

    我尚不确定以这种方式使用(ab)临时表空间的潜在后果,但是到目前为止,它并没有给我带来任何麻烦,并且比通过防止任一行损坏的替代方法要安全得多。索引。

    此操作的成功也很清楚地证明了PK索引是问题所在,因为这是临时表和永久表之间唯一的实际区别-在性能测试期间,两者均从零行开始。

结论:不要费心尝试使用ODP.NET将多于10万行的数据批量复制到索引的Oracle表中。删除索引(如果您实际上不需要它)或将数据“预加载”到另一个(非索引)表中。


我不确定要检查主键约束。我不得不将相同的数据批量插入Oracle表2次,并且Select *显示2条重复的行。在这种状态下,无法执行删除操作,但是截断表有助于恢复到干净状态。
bernd_k 2011年

@bernd_k:Delete不可能,因为索引是UNUSABLE。这是在大容量副本末尾进行约束检查的结果。
亚伦诺特,2011年

我正在运行PowerShell skript,从SQL Server数据读取器将bulkcopy调用到Oracle数据库中,所有具有主键的目标表都没有问题,最多205278行的表没有问题。但是我非常小心,在填充明细表之前先填充主表。我没有删除表上的任何其他索引,并且当表最初为空时,我没有任何问题。
bernd_k 2011年

@bernd_k:是的,在这个数量上我也没有太多问题(请参阅我的最后一段)。当您接触到数以百万计的人时,它会变得很糟糕。如果在每次批量复制后的某个时间清空表,也可能会有所不同(该表不会被清空,而是被附加到表中,并且您知道索引随着变大而变慢)。
亚伦诺特,2011年

也许它有助于当你做一个alter session set skip_unusable_indexes = true;
Wernfried Domscheit

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.