Оператор PL SQL UPDATE в L OOP занимает вечность - PullRequest
0 голосов
/ 09 июля 2020

Если я выполняю

UPDATE person 
SET CUSTOM2 = TIMESTAMP_DIFF(SYSTIMESTAMP,TO_TIMESTAMP (CUSTOM1, 'YYYY-MM-DD HH24:MI:SS.FF')) 
WHERE  person.id = 'p01';

, он обновляется нормально, но если я выполняю оператор обновления внутри l oop, он зависает навсегда

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 vcount: 1

, но когда я раскомментирую оператор обновления, он висит навсегда

1 Ответ

1 голос
/ 09 июля 2020

Я предполагаю, что предыдущее обновление не было зафиксировано, и оно сохраняет эти строки заблокированными , поэтому вы просто ждете фиксации (или отката).

В любом случае: зачем вам использовать вариант какой неоптимальный? Как вы уже видели, обычный UPDATE отлично справляется со своей задачей. Выполнение этого в al oop обновляет построчно, что обещает быть медленным за медленным. На вашем месте я бы не стал беспокоиться.

Если вы хотите узнать, кто кого блокирует, вы можете запросить Oracle просмотров словаря. На Inte rnet также доступно множество скриптов, посмотрите. Или, если вы используете какой-нибудь GUI - например, TOAD, который предлагает «Обозреватель схем», который позволяет вам легко просматривать эту информацию - используйте его.

Между тем, например, есть таблица TEST в Схема Скотта; Я обновил его за один сеанс как:

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

1 row updated.

SQL>

Затем я подключился к другому сеансу (также как Скотт) и запустил

SQL> update test set sal = 3000;

и - ничего не произошло. Вешает . Поэтому я подключился как 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.

...