批量收集问题

时间:2015-07-22 16:36:09

标签: oracle performance plsql cursor bulk-collect

我有一个程序,我需要使用批量收集从游标中获取数据。这种方法的问题是 - 有时记录正在处理,有时它们不是。我无法确定根本原因。当我尝试调试问题时,toad没有响应并且超时。这是代码。请帮忙!

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 个答案:

答案 0 :(得分:1)

看起来你已将exit评论为调试尝试的一部分 - 这就是导致Toad无法响应的原因,因为这意味着循环永不退出(正如Tony Andrews指出的那样)出)。

如果您拥有exit,那么如果光标查询找到少于100行,您将无法处理任何内容,因为即使某些数据是PRCURSOR%NOTFOUND,您也会看到exit实际检索。如果它找到超过100行,您将处理第一批,但是仍然会丢失最后一批少于100的记录。

因此,您需要将 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而不是FORALL,因此如果最后一个实际批次恰好是100行,则不会出现问题,下一个获得零行 - 它在 <label id="lblTest" /> 中什么也不做,然后退出。

this Oracle Magazine article的后半部分涵盖了此方案(&#39;踢了%NOTFOUND习惯&#39;)。