Проблема с массовым сбором
У меня есть процедура, где мне нужно получить данные из курсора с помощью массового сбора. Проблема с этим подходом заключается в том, что иногда записи обрабатываются, а иногда нет. Я не могу определить причину. Когда я пытаюсь отладить проблему, жаба не отвечает и время ожидания истекает. Вот код Пожалуйста помоги!
PROCEDURE GetPendingItems(pprogramidlst IN VARCHAR2, EventCur OUT cur)
AS
vSessionId NUMBER;
vDefaultValue svoltp.param.DefaultValue%TYPE;
TYPE EventRec IS TABLE OF TrigEventQueue.TrigEventQueueId%TYPE;
TYPE EventPartitionDate IS TABLE OF TrigEventQueue.PartitionDate%TYPE;
vEventRec EventRec;
vEventPartitionDate EventPartitionDate;
vOldestPossibleDate DATE;
vtrigeventqueueid VARCHAR2 (250);
vprogramidlst VARCHAR2 (250);
vETInterval number;
VCOUNT NUMBER;
VCOUNT1 NUMBER;
CURSOR PRCURSOR(vCount1 NUMBER) IS
SELECT TrigEventQueueId, PartitionDate FROM TRIGEVENTQUEUE A
WHERE TrigEventQueueId IN (SELECT TrigEventQueueId
FROM ( SELECT teq.TrigEventQueueId, teq.PartitionDate, teq.EventProcessingSessionId,teq.TrigEventStateId
FROM svoltp.TrigEventQueue teq,
programtrigevent pte,
trigevent te
WHERE teq.TrigEventStateId = gcEventStatePending
AND teq.EventProcessingSessionId IS NULL
AND teq.ProgramTrigEventId = pte.ProgramTrigEventId
AND pte.TrigEventId = te.TrigEventId
AND teq.PartitionDate >
(SYSDATE - (te.NumHoursUntilEventExpired / 24))
AND teq.PartitionDate > vOldestPossibleDate
ORDER BY teq.TrigEventCreatedTS) a
WHERE ROWNUM <= vCount1)
FOR UPDATE OF A.TrigEventQueueId, A.PARTITIONDATE SKIP LOCKED;
BEGIN
vSessionId := TrigEventSessionIdSeq.NEXTVAL;
vprogramidlst := pprogramidlst;
SELECT DefaultValue
INTO vDefaultValue
FROM svoltp.Param
WHERE ParamId = gcMaxPenEventsParam;
SELECT DefaultValue
INTO vETInterval
FROM svoltp.Param
WHERE ParamId = 2755;
-- Use MAX number of expiry hours to identify an oldest possible date/time that any event could be picked up for.
SELECT SYSDATE - (MAX (NumHoursUntilEventExpired) / 24)
INTO vOldestPossibleDate
FROM trigevent;
SELECT COUNT(1) INTO VCOUNT1
FROM ( SELECT teq.TrigEventQueueId, teq.PartitionDate
FROM svoltp.TrigEventQueue teq,
programtrigevent pte,
trigevent te
WHERE teq.TrigEventStateId = gcEventStatePending
AND teq.EventProcessingSessionId IS NULL
AND teq.ProgramTrigEventId = pte.ProgramTrigEventId
AND pte.TrigEventId = te.TrigEventId
AND teq.PartitionDate >
(SYSDATE - (te.NumHoursUntilEventExpired / 24))
AND teq.PartitionDate > vOldestPossibleDate
ORDER BY teq.TrigEventCreatedTS) a
WHERE ROWNUM <= vDefaultValue;
IF VCOUNT1 > 0 THEN
SELECT count(1) into vcount FROM ETINSTANCESTATUS
WHERE datediff ('SS', INSTANCEUPDATETIME, SYSDATE) < vETInterval;
if vcount > 0 then
vcount1 := round(vcount1/vcount);
else
vcount1 := vcount1;
end if;
END IF;
OPEN PRCURSOR(vcount1);
LOOP
FETCH PRCURSOR BULK COLLECT INTO vEventRec, vEventPartitionDate LIMIT 100;
-- EXIT WHEN PRCURSOR%NOTFOUND;
--SVOLTP.PKGSVOLTPLOCK.SLEEP(1);
FORALL i IN vEventRec.FIRST .. vEventRec.LAST
UPDATE svoltp.TrigEventQueue teq
SET teq.EventProcessingSessionId = vSessionId,
teq.TrigEventStateId = gcEventStateLocked, --6 : Locked State
teq.LastUser = 1003,
teq.LastUpdate = SYSDATE
WHERE teq.TrigEventQueueId = vEventRec (i)
AND teq.PartitionDate = vEventPartitionDate (i);
END LOOP;
COMMIT;
CLOSE PRCURSOR;
OPEN EventCur FOR
SELECT TrigEventQueueId, ProgramTrigEventId, PartitionDate
FROM svoltp.TrigEventQueue teq
WHERE teq.EventProcessingSessionId = vSessionId
AND teq.TrigEventStateId = gcEventStateLocked
AND teq.PartitionDate > vOldestPossibleDate;
EXCEPTION
WHEN OTHERS
THEN
OPEN EventCur FOR
SELECT 1
FROM DUAL
WHERE 1 = 2;
END GetPendingItems;
1 ответ
Похоже, вы закомментировали exit
как часть вашей попытки отладки - и это то, что заставляет Жабу перестать отвечать, поскольку это означает, что цикл никогда не завершается (как указал Тони Эндрюс).
С exit
где бы вы ни находились, вы ничего не обработаете, если запрос курсора найдет менее 100 строк, как вы увидите PRCURSOR%NOTFOUND
даже если некоторые данные были фактически получены. И если он найдет более 100 строк, вы обработаете первый пакет, но потом все равно потеряете записи из последнего пакета менее 100.
Так что вам нужно переместить exit
до конца цикла и измените условие:
LOOP
FETCH PRCURSOR BULK COLLECT INTO vEventRec, vEventPartitionDate LIMIT 100;
--SVOLTP.PKGSVOLTPLOCK.SLEEP(1);
FORALL i IN 1 .. vEventRec.COUNT
UPDATE svoltp.TrigEventQueue teq
SET teq.EventProcessingSessionId = vSessionId,
teq.TrigEventStateId = gcEventStateLocked, --6 : Locked State
teq.LastUser = 1003,
teq.LastUpdate = SYSDATE
WHERE teq.TrigEventQueueId = vEventRec (i)
AND teq.PartitionDate = vEventPartitionDate (i);
EXIT WHEN vEventRec.COUNT < 100;
END LOOP;
Я также изменил FORALL
цикл для использования 1..count
скорее, чем first..last
так что проблем не будет, если последний фактический пакет будет ровно 100 строк, а следующий получит ноль строк - он ничего не будет делать в FORALL
и затем выход.
Этот сценарий описан во второй половине этой статьи в Oracle Magazine ("Kicking the %NOTFOUND Habit").