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;
答案 0 :(得分: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
。包括这个将:
答案 1 :(得分:1)
我认为你应该改变你的CURSOR并在循环语句中点击UPDATE
此外,我更喜欢使用RowID
表示更新语句,使用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的评论编辑了一些部分。
我也根据versions 9i and 10g进行了一些更改
使用TREAT
的限制已在11g中删除