将 oracle DB 中的 100 万条记录更新为 10k 批;

use*_*775 0 sql database oracle plsql sqlplus

我必须将 oracle db 中的表更新为 10k 的批次。

我试过这个:

BEGIN
        WHILE (true) LOOP
        UPDATE TOP (10000) CUSTOMERS SET ACTIVE = 'N' WHERE ACTIVE='Y';
        IF sql%notfound THEN
                EXIT;
        END IF;
        COMMIT;
        END LOOP;
END;
Run Code Online (Sandbox Code Playgroud)

它不起作用,因为 plsql 不支持 top。

有什么建议?

Car*_*rna 5

你的 pl/SQL 块,使用 JVA 的建议,应该像这样完成(因为你是 pl/sql 的新手,我正在添加一些你可能感兴趣的语法建议):

BEGIN
      -- WHILE (TRUE) can be omitted: "loop ... end loop;" 
      --  already is an endless loop
      LOOP
         UPDATE CUSTOMERS 
             SET ACTIVE = 'N' 
         WHERE ACTIVE='Y'
           AND rownum <= 1000;  
         exit when sql%notfound; -- notice that exit accepts "when condition"
         --IF sql%notfound THEN  -- you can avoid a if/endif by using "exit when"
         --   EXIT;
         -- END IF;
         COMMIT;
   END LOOP;
   commit; -- you missed this commit for the last iteration
END;
Run Code Online (Sandbox Code Playgroud)

不要试图将“commit”放在“exit when sql%notfound”之前:在“commit”之后 sql%notfound 总是假的,你的循环真的是无止境的。

让我指出,为了提高效率,这种方法需要对“ACTIVE”列进行索引!

如果您在“活动”列上没有索引,则每次“更新”都将被迫从头开始重新启动全表扫描,以找到下一个仍需要更新的 1000 条记录。

我提议的另一种方法使用了一些高级 PL/SQL 功能,作为学习者,您可能会感兴趣(rowid、“table of”、光标批量获取和“forall”)并且只对要更新的表进行一次扫描所以(在没有索引的情况下)它比以前的方法表现更好。请记住,如果您有索引,这会较慢(但使用 foralls、批量收集和 rowid 访问,它并没有那么慢),但在事情更复杂的情况下(例如:当 where 条件时,它可以派上用场)需要使用无法更快的复杂连接访问其他表中的数据)。在某些情况下,“where”是如此复杂和缓慢,以至于您真的不想使用“where rownum<=1000”方法一遍又一遍地重新执行它。

    declare
      type rowid_array is table of rowid;

      ids rowid_array;

      cursor cur is 
         select rowid as id 
         from CUSTOMERS 
         where ACTIVE='Y';

    begin
      open cur;
      loop
         fetch cur bulk collect into ids limit 1000;
         exit when ids.count = 0;

         forall c in ids.first .. ids.last 
            update CUSTOMERS set  ACTIVE='N';

         commit;     
      end loop;
    end;
Run Code Online (Sandbox Code Playgroud)

  • 我收到 PLS-00435:没有 BULK In-BIND 的 DML 语句不能在 FORALL 中使用。有什么建议吗? (2认同)