【问题标题】:Commit in PLSQL loop for update在 PLSQL 循环中提交以进行更新
【发布时间】:2015-06-25 10:42:04
【问题描述】:

我在我的 java 程序中使用以下函数将列从临时表复制到主表。

FUNCTION TEST(TBL_NAME VARCHAR2, TMP_TBL_NAME VARCHAR2, ID_COL VARCHAR2, REQ_COL VARCHAR2, BATCH_SIZE NUMBER) RETURN NUMBER AS
BEGIN
EXECUTE IMMEDIATE 'SELECT COUNT(1) FROM ' || TMP_TBL_NAME INTO TOTAL_RECORDS;
OFFSET := 0;
WHILE OFFSET < TOTAL_RECORDS
LOOP
  MAX_RESULTS := OFFSET + BATCH_SIZE;
  EXECUTE IMMEDIATE 'SELECT ' || ID_COL || ', ' || REQ_COL || ' FROM ' || TMP_TBL_NAME || ' WHERE SEQ_NBR BETWEEN :OFFSET AND :MAX_RESULTS' BULK COLLECT INTO SEQ_IDS, REQ_COL_VALUESS USING OFFSET, MAX_RESULTS;
  FORALL IND IN SEQ_IDS.FIRST .. SEQ_IDS.LAST
    EXECUTE IMMEDIATE 'UPDATE ' || TBL_NAME || ' SET ' || REQ_COL || ' = :REQ_COL_VAL WHERE ' || ID_COL || ' = :ID_COL_VAL' USING REQ_COL_VALUESS(IND), SEQ_IDS(IND);
  OFFSET := MAX_RESULTS;
  COMMIT;
END LOOP;
RETURN 0;
EXCEPTION
WHEN OTHERS THEN
  RAISE CUST_EXCEPTION; 
END;

预期结果是,当我以 100000 的 batch_size 运行时,每次提交都必须更新 100000 条记录,因为我上面使用的 id_col 是主键。运行 java 程序后,在中间检查主表中的更新时,我可以看到正在更新的批次 6469 或 80148 的记录。

临时表中大约有 1000 万条记录。如果我删除了 forall 更新语句,我将以适当的批量大小迭代数据。

谁能解释一下为什么会这样

【问题讨论】:

    标签: java jdbc plsql


    【解决方案1】:

    1) 您的临时表中有多少条记录?

    2) 为什么不使用 sys_refcursor 和使用 limit 批量收集?

    declare 
     v_cursor sys_refcursor; 
     res1 sys.DBMS_DEBUG_VC2COLL; -- - predefined collection in oracle 
     res2 sys.DBMS_DEBUG_VC2COLL;
     v_batch_size pls_integer := 50;
    begin 
     open v_cursor for 'Select 1,2 from dual connect by level < 10000';
     loop
     fetch v_cursor bulk collect into res1,res2 limit v_batch_size;
     exit when res1.count =0;
        dbms_output.put_line(res1.count);
      -- forall ind in res1.first .. res1.last loop e.g 
      -- commit;
     end loop;
      close v_cursor;
    end;
    

    【讨论】:

    • 我也试过用光标。我遇到的问题不在于迭代,而在于 forall 的更新。对于临时表中的所有记录,主表中有一条记录。我检查时更新的记录数仍然不等于我的 batch_size 的倍数。
    • 例如 BATCH_SIZE = 10 迭代 1 offset = 0, max_result = 10;迭代 2 偏移 = 10,max_result = 20; select seg from (Select level seg from dual connect by level
    【解决方案2】:
    -- first iteration offset= 0 , max_result = 10 
    -- v_batch_size = 10
    -- offset := 0 
    --  MAX_RESULTS := 10 
    select seg from ( Select level seg from dual connect by level < 1000)  where seg between 0 and 10;
    -- secound iteration 
    -- v_batch_size = 10
    -- offset := 10 
    --  MAX_RESULTS := 20 
    select seg from ( Select level seg from dual connect by level < 1000) where seg between 10 and 20;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-25
      相关资源
      最近更新 更多