【问题标题】:Performance problem with Oracle BULK FETCH and FORALL insertOracle BULK FETCH 和 FORALL 插入的性能问题
【发布时间】:2010-10-09 00:13:03
【问题描述】:

我正在尝试尽快将记录从一个表复制到另一个表。

目前我有一个与此类似的简单光标循环:

FOR rec IN source_cursor LOOP
   INSERT INTO destination (a, b) VALUES (rec.a, rec.b)
END LOOP;

我想把它加速到超快,所以我正在尝试一些 BULK 操作(一个 BULK FETCH,然后是一个 FORALL 插入):

这是我对批量选择/forall 插入的内容。

DECLARE 
  TYPE t__event_rows IS TABLE OF _event%ROWTYPE;
  v__event_rows t__event_rows;

  CURSOR c__events IS
    SELECT * FROM _EVENT ORDER BY MESSAGE_ID;
BEGIN
  OPEN c__events;
  LOOP
    FETCH c__events BULK COLLECT INTO v__event_rows LIMIT 10000;  -- limit to 10k to avoid out of memory

    EXIT WHEN c__events%NOTFOUND;

    FORALL i IN 1..v__event_rows.COUNT SAVE EXCEPTIONS
      INSERT INTO destinatoin
        ( col1, col2, a_sequence) 
        VALUES 
        (  v__event_rows(i).col1,  v__event_rows(i).col2, SOMESEQEUENCE.NEXTVAL );


  END LOOP;
  CLOSE c__events;


END;

我的问题是,到目前为止,我没有看到性能上有任何大的提升。根据我的阅读,它应该快 10 到 100 倍。

我是否错过了某个地方的瓶颈?

【问题讨论】:

  • 对于 100,000 行,即使是批量插入也需要大约 300 (!) 秒
  • 您的 SELECT 中有 ORDER BY 的原因吗?对 100,000 行进行排序可能相当昂贵,而且这似乎没有必要。此外,您的 %NOTFOUND 检查需要在您的 FORALL 之后进行 - 否则,如果您在最后一次迭代中获取少于 10,000 行,您将不会插入这些行。
  • 谢谢!我将删除订单,但我认为它不会让我达到我正在寻找的速度......我将尝试获得 tkprof 分析并稍后更新。 %NOTFOUND 的好收获
  • 您的目标表中有触发器吗?另外,如果您只是将数据从一个表复制到另一个表,您可以使用 SQL 语句而不是 PL/SQL 吗?

标签: oracle plsql query-optimization bulkinsert


【解决方案1】:

与简单的INSERT+SELECT 相比,您的代码的唯一好处是您可以保存异常,另外(正如贾斯汀指出的)您有一个毫无意义的ORDER BY,这使得它做了很多无意义的工作.无论如何,您没有任何代码可以对保存的异常执行任何操作。

我只是将其实现为INSERT+SELECT

【讨论】:

  • 并且您可以在 INSERT 上使用 LOG ERRORS 子句来保存异常。
【解决方案2】:

在编码本身需要循环之前,您不必不必要地使用循环。

【讨论】:

  • 这应该是评论,而不是答案。
  • 是的,但代码需要一些提示以解决更好的性能问题。
  • 是的,这就是为什么它应该是一个评论:)
猜你喜欢
  • 2014-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多