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,请他们帮忙。