总结一下细节:我们需要将大约 500 万行暂存到供应商 (Oracle) 数据库中。使用 (ODP.NET) 批量处理 500k 行时,一切都很好OracleBulkCopy
,但是当我们尝试扩展到 5M 时,性能一旦达到 1M 标记就会开始缓慢爬行,随着更多行的加载而逐渐变慢,最终3小时左右后超时。
我怀疑它与桌子上的主键有关,但我一直在搜索 Oracle 论坛和 Stack Overflow 以获取信息,而且我正在阅读的很多内容都与此相矛盾(而且,很多帖子似乎相互矛盾) . 我希望有人可以直接记录有关该过程的一些密切相关的问题:
该类是否
OracleBulkCopy
使用常规或直接路径加载?有什么方法可以证实这一点,一种或另一种?假设它确实使用直接路径加载:Oracle 是否会在加载期间自动将所有索引设置为不可用并在之后将它们重新联机?我已经阅读了几篇关于此的声明,但再次无法确认。
如果 #2 为真,那么在我启动大容量复制操作之前,表上的索引是否应该有所不同?如果是这样,为什么?
与#3相关,一般来说,在使用不可用索引的批量加载与在加载之前实际删除索引并在之后重新创建索引之间是否有任何实际区别?
如果 #2不正确,或者如果有一些我不理解的警告,那么在批量加载之前显式使索引不可用,然后 显式重建它会有什么不同吗?
随着越来越多的记录被添加,除了索引构建之外,还有什么其他可能导致批量复制操作逐渐变慢的吗?(也许与日志记录有关,尽管我希望不会记录批量操作?)
如果除了首先删除 PK/index 之外真的没有其他方法可以让性能达到最佳状态,我可以采取哪些步骤来确保索引不会完全消失,即如果与数据库的连接丢失过程的中间?
再经过几天的阅读和实验,我能够(大部分)回答其中的很多问题:
我发现这隐藏在ODP.NET 文档中(具有讽刺意味的是,不在
OracleBulkCopy
文档中):所以看起来它确实使用了直接路径。
我可以通过执行大型批量复制操作并从 SQL Developer 获取索引属性来验证这一点。该索引确实显示为
UNUSABLE
在进行大容量复制时。 但是,我还发现,如果索引在某个状态下启动OracleBulkCopy.WriteToServer
,它将拒绝运行,所以显然这里还有更多内容,因为如果它像禁用和重建索引一样简单,那么它不应该关心初始状态。UNUSABLE
如果索引也是一个约束,它确实会有所不同。在上面链接的文档中找到了这个小宝石:
文档对加载过程中发生的事情有点模糊,尤其是主键,但有一件事是绝对肯定的 -使用主键与没有主键的行为不同。由于
OracleBulkCopy
很乐意让您违反索引约束(并在完成后将索引置于UNUSABLE
状态),我的直觉是它在批量复制期间构建PK 索引,但只是在之后才验证它。我不确定观察到的差异是在 Oracle 本身内部还是只是
OracleBulkCopy
. 陪审团还在这个问题上。OracleBulkCopy
如果索引最初处于该状态,则会引发异常UNUSABLE
,因此这确实是一个有争议的问题。如果还有其他因素,索引(尤其是 PK 索引)仍然是最重要的,我通过以下方式发现:
创建具有相同架构的全局临时表(使用
CREATE AS
),然后批量复制到临时表中,最后INSERT
从临时表中将普通旧表复制到真实表中。由于临时表没有索引,所以批量复制发生得非常快,最终INSERT
也很快,因为数据已经在一个表中(我还没有尝试附加提示,因为一个 5M 行的表到表复制已经花费了不到 1 分钟)。我还不确定(ab)以这种方式使用临时表空间的潜在后果,但到目前为止,它并没有给我带来任何麻烦,而且它比防止任一行损坏的替代方法更安全或索引。
这个成功也非常清楚地表明 PK 索引是问题所在,因为这是临时表和永久表之间唯一实际的区别——在性能测试期间都从零行开始。
结论:不要费心尝试使用 ODP.NET 将超过 100k 行大容量复制到索引 Oracle 表中。删除索引(如果您实际上不需要它)或将数据“预加载”到不同的(非索引)表中。
这是 Oracle 的一篇文章,它解释了何时使用批量插入有利或何时不利。此外,还可以深入了解数据库级别发生的情况。
http://docs.oracle.com/cd/B28359_01/server.111/b28319/ldr_modes.htm