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

updating 1 million records in oracle DB as batch of 10k;

我必须将 oracle 数据库中的 table 更新为 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;

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

有什么建议吗?

如果您在 CUSTOMERS table 上有自动递增的合成 ID 列,那么您可以简单地使用 WHERE 条件说

WHERE ID <= 10000
UPDATE CUSTOMERS 
SET ACTIVE = 'N' 
WHERE ACTIVE='Y'
  AND ROWNUM <= 10000; -- first 10k rows

jva 的 答案之上添加以处理所有行而不更改每个批次的查询:

更新前:

select count(1) from cust ; --1000000

select distinct active from cust ; -- Y

更新:

Begin
for i in 1..100
loop
update cust  set Active = 'N' where ACTIVE = 'Y' 
and rownum <= 10000;
-- dbms_output.put_line ('i value :  ' || i );
commit;
end loop;
dbms_output.put_line ('All rows updated ' );
end;

输出:

All rows updated 

Statement processed.

3.77 seconds

之后:

select distinct active from cust ; -- N

你的 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;

不要试图在“sql%notfound 时退出”之前放置“commit”:在“commit”之后 sql%notfound 始终为 false,您的循环将真的没完没了

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

如果您在“活动”列上没有索引,则每次“更新”都将被迫从头开始进行完整的 table 扫描,只是为了找到下 1000 条仍需要的记录待更新。

我提议的另一种方法使用了一些高级 PL/SQL 功能,作为学习者,您可能会感兴趣(rowid、“table of”、cursor bulk fetchs 和“forall”)并且只扫描一次 table 进行更新,因此(在没有索引的情况下)它比以前的方法执行得更好。 请记住,如果您有索引,这会更慢 (但使用 foralls、批量收集和 rowid 访问,它并没有那么慢),但在某些情况下它会很方便更复杂(例如:当 where 条件需要使用无法提高速度的复杂连接从其他 table 访问数据时)。在某些情况下,“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'
            where rowid = ids(c);
            
         commit;     
      end loop;
    end;