Oracle 循环中的PLSQL UPDATE语句需要花费很长时间

Oracle 循环中的PLSQL UPDATE语句需要花费很长时间,oracle,plsql,Oracle,Plsql,如果我执行 UPDATE person SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) WHERE person.id = 'p01'; 它更新得很好,但如果我在循环中执行update语句,它将永远挂起 DECLARE TYPE person_ids_t IS table of person.id%type index by PLS_

如果我执行

UPDATE person 
SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) 
WHERE  person.id = 'p01';
它更新得很好,但如果我在循环中执行update语句,它将永远挂起

DECLARE
   
    TYPE person_ids_t IS table of person.id%type index by PLS_INTEGER;
    ids_collection person_ids_t;
    CURSOR cur  IS  select id from person where CUSTOM1 is not null;
   
BEGIN   
    OPEN cur;   
   
--    LOOP   
        FETCH cur   BULK COLLECT INTO ids_collection   LIMIT 10;   
--        EXIT WHEN ids_collection.COUNT = 0;   
   
        FORALL idx IN 1 .. ids_collection.COUNT
            UPDATE person 
            SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) 
            WHERE  person.id = ids_collection(idx);
   
      COMMIT;   
--   END LOOP;  
   CLOSE cur;  
END;
当我执行上述块时,ScriptRunner将永远挂起,我必须强制退出。 不知道为什么

甚至将脚本更改为

set SERVEROUTPUT ON;
DECLARE
    c_id person.id%type;
    CURSOR cur  IS  select id from person where CUSTOM1 is not nul;
    
    vcount integer :=0;
   
BEGIN   
    OPEN cur;   
   
    LOOP 
        FETCH cur into c_id;
        EXIT WHEN cur%notfound; 
 
   
       
--        UPDATE person 
--        SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) 
--        WHERE  person.id = c_id;
        
        dbms_output.put_line('c_id: ' || c_id); 
        
        vcount := vcount + 1;
        IF vcount = 1 THEN
            EXIT;
        END IF; 
   END LOOP;  
   CLOSE cur;  
   
   dbms_output.put_line('vcount: ' || vcount); 
   
END;
/
如果我执行这个,它会打印出来 c_id:p01 总数:1


但是,当我取消对update语句的注释时,它将永远挂起

我的猜测是,以前的更新没有提交,并且它将这些行保持锁定,因此您只是在等待提交(或回滚)

DECLARE
   
    TYPE person_ids_t IS table of person.id%type index by PLS_INTEGER;
    ids_collection person_ids_t;
    CURSOR cur  IS  select id from person where CUSTOM1 is not null;
   
BEGIN   
    OPEN cur;   
   
--    LOOP   
        FETCH cur   BULK COLLECT INTO ids_collection   LIMIT 10;   
--        EXIT WHEN ids_collection.COUNT = 0;   
   
        FORALL idx IN 1 .. ids_collection.COUNT
            UPDATE person 
            SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) 
            WHERE  person.id = ids_collection(idx);
   
      COMMIT;   
--   END LOOP;  
   CLOSE cur;  
END;
无论如何:你为什么要使用次优的选项?正如您已经看到的,一个普通的
更新
可以很好地完成这项工作。在一个循环中进行更新就是一行一行地更新,这意味着一步一步地更新。如果我是你,我就不麻烦了


如果您想找到谁阻止了谁,可以查询Oracle字典视图。互联网上也有很多脚本,看看吧。或者,如果你使用一些像TOAD这样的GUI,它提供了“模式浏览器”,可以让你很容易地看到这些信息,那么就使用它

同时,举个例子,在Scott的模式中有
TEST
表;我在一次会议中更新了它:

SQL> update test set sal = 2000 where empno = 7369;

1 row updated.

SQL>
然后我连接到另一个会话(也称为Scott)并运行

什么也没发生。它挂着。因此,我以SYS(它可以访问所有字典视图;如果您有其他具有适当权限的用户,请使用它)的身份连接,并以以下方式查询数据库:

SQL> select
  2     (select username from v$session where sid = a.sid) blocker,
  3     --
  4     a.sid,
  5     ' is blocking ',
  6     --
  7     (select username from v$session where sid = b.sid) blockee,
  8     --
  9     b.sid
 10  from v$lock a join v$lock b on a.id1 = b.id1 and a.id2 = b.id2
 11  where a.block = 1
 12    and b.request > 0;

BLOCKER                SID 'ISBLOCKING'  BLOCKEE                SID
--------------- ---------- ------------- --------------- ----------
SCOTT                  141  is blocking  SCOTT                   92

SQL>

所以,是的-我的第141次会话阻塞了我的另一次会话92。我应该在会话141中提交(或回滚)以让会话92继续。

您的person.id列是否已编制索引?这样做是有目的的。有没有一种方法可以让我知道哪些行被锁定,以及如何释放它们;请看一看。谢谢,因为我已经被迫退出了SQL开发工具,等待时间是否有限制,或者我是否应该通知DBA终止它:)好吧,Oracle最终会终止它,迟早(比如说,半小时左右);我会打电话给DBA,请他们帮忙。