0
create or replace procedure Proc_1(P_IN_TABLE_NAME VARCHAR2)
AS
CURSOR T_FACT
IS
SELECT T_ID,T_VER,D_T_ID
from O_T_FACT
where  T_ID is not null
and T_VER is not null;

TYPE call_tab IS TABLE OF O_T_FACT%rowtype;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN

   OPEN T_FACT;  
   LOOP 

      EXIT WHEN T_FACT%NOTFOUND ;   

            FETCH T_FACT BULK COLLECT INTO call_data_rec LIMIT no_of_rec;                   
            EXIT WHEN call_data_rec.count = 0;

                       FOR j IN 1..call_data_rec.COUNT
                        loop
                        UPDATE  G_FACT GL set
                        GL.T_ID = call_data_rec(j).T_ID, 
                        GL.T_VER =call_data_rec(j).T_VER,
                        GL.TRANS_FLAG='Y'
                        WHERE GL.G_T_ID = call_data_rec(j).D_T_ID
                        AND GL.T_ID IS NULL 
                        AND GL.T_VER IS NULL;             

                        rec_count := rec_count + 1;                       
                        if mod(rec_count,10000) = 0 then
                        commit;
                        end if;               
                        end loop; 

   end loop;
   CLOSE T_FACT;
   END IF;
End;

这个特定的过程需要很长时间,还有其他方法可以写吗?这可以在单个更新语句中完成吗?

正如下面所建议的,除了 PLS-00436 给出的错误之外,我已经厌倦了所有的事情:实施限制:无法引用 BULK In-BIND 记录表的字段

面向所有人的新代码

create or replace procedure Proc_update_T_ID(P_IN_TABLE_NAME VARCHAR2)
AS
no_of_rec number := 1000;
CURSOR T_and_V_FACT
IS
SELECT O_T_FACT.T_ID, O_T_FACT.T_VER, O_T_FACT.Downstream_T_ID, G_FACT.rowid row_id,
From O_T_FACT, G_FACT
WHERE O_T_FACT.T_ID IS NOT NULL AND G_FACT.G_T_ID = O_T_FACT.Downstream_T_ID
AND T_VER is not null
AND G_FACT.T_VER IS NULL;

TYPE call_tab IS TABLE OF T_and_V_FACT%rowtype index by binary_integer;
call_data_rec call_tab;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN
        IF T_and_V_FACT%ISOPEN THEN
            CLOSE T_and_V_FACT;
        END IF;    

        open T_and_V_FACT;

        LOOP

            FETCH T_and_V_FACT BULK COLLECT
            INTO call_data_rec LIMIT no_of_rec;

            FORALL j IN call_data_rec.FIRST .. call_data_rec.LAST    
            UPDATE  G_FACT GL set
                        GL.T_ID = call_data_rec(j).T_ID, 
                        GL.T_VER =call_data_rec(j).T_VER,
                        GL.TRANS_FLAG='Y'
            WHERE GL.rowid = call_data_rec(j).row_id;      

            COMMIT;                  
            call_data_rec.DELETE;
        EXIT WHEN T_and_V_FACT%NOTFOUND;      
        END LOOP;

        CLOSE T_and_V_FACT;
   End if;

END Proc_1;
4

2 回答 2

2

在我看来,您可以将其重写为单个语句,如下所示:

update G_FACT GL
set    (GL.T_ID, GL.T_VER, GL.TRANS_FLAG) = 
            (select T_ID,T_VER, 'Y'
              from   O_T_FACT F
              where  F.T_ID is not null
              and    F.T_VER is not null
              and    GL.G_T_ID = F.D_T_ID)
where  exists (select null
               from   O_T_FACT F
               where  F.T_ID is not null
               and    F.T_VER is not null
               and    GL.G_T_ID = F.D_T_ID)
and    GL.T_ID is null
and    GL.T_VER is null; 

如果这不起作用,那么您应该能够通过将for循环转换为forall语句来获得显着收益:

 FORALL j IN 1..call_data_rec.COUNT
    UPDATE  G_FACT GL set
    GL.T_ID = call_data_rec(j).T_ID, 
    GL.T_VER =call_data_rec(j).T_VER,
    GL.TRANS_FLAG='Y'
    WHERE GL.G_T_ID = call_data_rec(j).D_T_ID
    AND GL.T_ID IS NULL 
    AND GL.T_VER IS NULL;    

此外,重新考虑是否需要commit在循环中使用它。包括这将:

  • 减慢您的处理速度
  • 增加命中 ORA-1555s 的机会
  • 可能使您的数据处于不一致的状态
于 2013-03-01T08:59:48.537 回答
1

我认为您应该更改 CURSOR 并在循环语句中点击 UPDATE
我更喜欢使用RowIDfor update 语句和LIMIT获取游标的大小以及FOR ALL 最大性能和内存管理。我们需要定义一个新类型:

CREATE TYPE my_rec AS OBJECT
  ( T_ID NUMBER
  , T_VER number
  , row_id UROWID)
  );

然后使用Proc_1可以服务:

create or replace procedure Proc_1(P_IN_TABLE_NAME VARCHAR2)
AS
no_of_rec number := 1000;
CURSOR T_and_V_FACT
IS
SELECT T_FACT.T_ID, T_FACT.T_VER, T_FACT.D_T_ID, G_FACT.rowid row_id,
  From O_T_FACT, G_FACT
 WHERE T_FACT.T_ID IS NOT NULL AND G_FACT.G_T_ID = O_T_FACT.D_T_ID
   AND T_VER is not null
      -- AND G_FACT.T_ID IS NULL -- not requierd
   AND G_FACT.T_VER IS NULL;

TYPE call_tab IS TABLE OF T_and_V_FACT%rowtype index by binary_integer;
call_data_rec call_tab;

BEGIN
   IF P_IN_TABLE_NAME ='G_FACT' THEN
   IF T_and_V_FACT%ISOPEN THEN
      CLOSE T_and_V_FACT;
   END IF;    
   open T_and_V_FACT;

 LOOP
      FETCH T_and_V_FACT BULK COLLECT
        INTO call_data_rec LIMIT no_of_rec;

      FORALL j IN call_data_rec.FIRST .. call_data_rec.LAST    
       UPDATE  G_FACT GL set
                        GL.T_ID = TREAT(call_data_rec(j) AS my_rec).T_ID, 
                        GL.T_VER =TREAT(call_data_rec(j) AS my_rec).T_VER,
                        GL.TRANS_FLAG='Y'
      WHERE GL.rowid = TREAT(call_data_rec(j) AS my_rec).row_id;      

      COMMIT;                  
      call_data_rec.DELETE;
      EXIT WHEN T_and_V_FACT%NOTFOUND;      
    END LOOP;
    CLOSE T_and_V_FACT;
   End if;
  END Proc_1;

我根据@Ben 的评论编辑了一些部分。
我还根据版本 9i 和 10g 做了一些更改11g 中删除
了使用限制TREAT

于 2013-03-02T10:23:36.510 回答