【问题标题】:Should FORALL place outside of for loop?FORALL 应该放在 for 循环之外吗?
【发布时间】:2017-07-11 14:14:29
【问题描述】:

我是 PL/SQL 的新手。
我决定使用以下 SQL 向表中插入数千条记录。但是,将 FORALL 语句放在 for 循环之外是否正确?
将 FORALL 语句移到 for 循环块中会更好吗?谢谢。

DECLARE

   CURSOR books_cur
   IS
    SELECT book_id, book_type
    FROM books
    WHERE book_category = 'PROGRAMMING';

   TYPE book_ids_t IS TABLE OF 
    books.book_id%TYPE;

   l_book_ids   book_ids_t := book_ids_t();

BEGIN
   FOR i IN books_cur LOOP
    IF(i.book_type = 'PLSQL') THEN
        l_book_ids.EXTENDS;
        l_book_ids(l_book_ids.LAST) := i.book_id;
    END IF;
   END LOOP;

   FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
    INSERT INTO table_a (book_id) VALUES l_book_ids(i);
END;

【问题讨论】:

  • 顺便说一句,if 条件周围不需要括号。它们不会破坏任何东西,但它们很混乱,编译器会忽略它们。

标签: sql oracle plsql oracle11g


【解决方案1】:

“将 FORALL 语句移到 for 循环块内是否更好”

没有。 FORALL 是一个集合操作。您需要每个工作单元执行一次,而不是每行一次。

" 向表中插入数千条记录"

请记住,集合保存在会话内存中。这意味着当您处理大量记录时,您需要更加注意内存管理。

所以你可能想分批工作,像这样:

BEGIN
   FOR i IN books_cur LOOP
        IF(i.book_type = 'PLSQL') THEN
            l_book_ids.EXTENDS;
            l_book_ids(l_book_ids.LAST) := i.book_id;
        END IF;
        if l_book_ids.count() = 1000 -- say
        then 
          FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
              INSERT INTO table_a (book_id) VALUES l_book_ids(i);
          l_book_ids.delete();
        end if; 
     END LOOP;
     FORALL i IN l_book_ids.FIRST..l_book_ids.LAST
        INSERT INTO table_a (book_id) VALUES l_book_ids(i);    
END;

此版本的代码以 1000 条为一组插入记录,并使用补充 FORALL 语句来捕获可能少于 1000 条记录的最后一批。

但是,实现示例的最有效方法仍然是

INSERT INTO table_a (book_id) 
SELECT book_id
FROM books
WHERE book_category = 'PROGRAMMING'
and  book_type = 'PLSQL';

【讨论】:

  • 您指出我真正担心的是内存使用情况!非常感谢。
【解决方案2】:

不,您的 FORALL 位于正确的位置。当然,你的示例程序根本不需要这个,可以写成:

BEGIN
INSERT INTO table_a (book_id)
SELECT book_id
    FROM books
    WHERE book_category = 'PROGRAMMING'
      AND book_type = 'PLSQL';
END;

但我知道你有兴趣学习 FORALL 概念,而不是编写最简单的代码!

【讨论】:

    【解决方案3】:

    在您的示例中,FORALL 需要集合 l_book_ids 作为输入。 在 FOR 循环内,集合尚未完全创建,因此您不能对其使用 FORALL。 正如 APC 所提到的,FORALL 是一个语句,您不能将其分解为多个步骤 - 事实上这是它的优势 - 它可以快速完成工作,一次完成。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-02-28
      • 1970-01-01
      • 1970-01-01
      • 2020-02-05
      • 2020-04-05
      • 1970-01-01
      相关资源
      最近更新 更多