我正在尝试使用 BULK COLLECT 和 FORALL 来加快我需要进行的更改。我正在使用 2 个游标,第一个返回 +6000 条记录,我需要这个游标的参数来执行第二个游标,它必须为第一个记录的每条记录执行 300 次更新。在数据库中运行需要 2 个小时,我正在尝试改进代码以减少这种情况。你能帮助我吗?
我的代码:
DECLARE
TYPE P_REC IS RECORD(
COD_1 NUMBER(10),
COD_2 NUMBER(10)
);
TYPE P_REC_ARRAY IS TABLE OF P_REC INDEX BY PLS_INTEGER;
REC P_REC_ARRAY;
CURSOR CR_PERSON IS
SELECT COD_1, COD_2 FROM PERSON;
TYPE CONSTRAINT_REC IS RECORD(
TABLE_NAME VARCHAR2(30),
COLUMN_NAME VARCHAR2(30),
CONSTRAINT_NAME VARCHAR2(30),
SQL1 VARCHAR2(200),
SQL2 VARCHAR2(200)
);
TYPE CONSTRAINT_REC_ARRAY IS TABLE OF CONSTRAINT_REC INDEX BY PLS_INTEGER;
P_CONSTRAINT CONSTRAINT_REC_ARRAY;
CURSOR CR_CONSTRAINT (cod_to NUMBER, cod_from NUMBER) IS
SELECT
FK.TABLE_NAME
,COL.COLUMN_NAME
,FK.CONSTRAINT_NAME
,'ALTER TABLE '||FK.TABLE_NAME||' MODIFY CONSTRAINT '||FK.CONSTRAINT_NAME||' DISABLE' SQL1
,'ALTER TABLE '||FK.TABLE_NAME||' MODIFY CONSTRAINT '||FK.CONSTRAINT_NAME||' ENABLE' SQL2
FROM ALL_CONSTRAINTS PK
JOIN ALL_CONSTRAINTS FK ON (PK.OWNER=FK.OWNER AND PK.CONSTRAINT_NAME=FK.R_CONSTRAINT_NAME AND FK.CONSTRAINT_TYPE='R')
JOIN DBA_CONS_COLUMNS COL ON (COL.OWNER=FK.OWNER AND FK.CONSTRAINT_NAME=COL.CONSTRAINT_NAME)
WHERE PK.OWNER='OWNER'
AND PK.TABLE_NAME = 'PERSON'
AND PK.CONSTRAINT_TYPE IN ('P','U');
update_sql VARCHAR2(200);
BEGIN
BEGIN
/* DISABLE CONSTRAINTS */
OPEN CR_CONSTRAINT(NULL,NULL);
FETCH CR_CONSTRAINT BULK COLLECT INTO P_CONSTRAINT;
CLOSE CR_CONSTRAINT;
IF P_CONSTRAINT.COUNT > 0 THEN
FOR i IN P_CONSTRAINT.FIRST .. P_CONSTRAINT.LAST
LOOP
EXECUTE IMMEDIATE P_CONSTRAINT(i).SQL1;
END LOOP;
END IF;
/* FROM/TO */
OPEN CR_PERSON;
FETCH CR_PERSON BULK COLLECT INTO REC;
CLOSE CR_PERSON;
IF REC.COUNT > 0 THEN
FOR j IN REC.FIRST .. REC.LAST
LOOP
OPEN CR_CONSTRAINT(REC(j).COD_2,REC(j).COD_1);
FETCH CR_CONSTRAINT BULK COLLECT INTO P_CONSTRAINT;
CLOSE CR_CONSTRAINT;
IF P_CONSTRAINT.COUNT > 0 THEN
FOR l IN P_CONSTRAINT.FIRST .. P_CONSTRAINT.LAST
LOOP
/* Here i want do FORALL, but i don't know how with parameters. When a TABLE and COLUMN is parameter. */
update_sql := 'UPDATE '||P_CONSTRAINT(l).TABLE_NAME||' SET '||P_CONSTRAINT(l).COLUMN_NAME||'='||REC(j).COD_2||' WHERE '||P_CONSTRAINT(l).COLUMN_NAME||'='||REC(j).COD_1;
EXECUTE IMMEDIATE update_sql;
END LOOP;
END IF;
END LOOP;
FORALL m IN REC.FIRST .. REC.LAST
UPDATE PERSON SET CODIGO = REC(m).COD_2 WHERE CODIGO = REC(m).COD_1;
END IF;
/* ENABLE CONSTRAINTS */
OPEN CR_CONSTRAINT(NULL,NULL);
FETCH CR_CONSTRAINT BULK COLLECT INTO P_CONSTRAINT;
CLOSE CR_CONSTRAINT;
IF P_CONSTRAINT.COUNT > 0 THEN
FOR z IN P_CONSTRAINT.FIRST .. P_CONSTRAINT.LAST
LOOP
EXECUTE IMMEDIATE P_CONSTRAINT(z).SQL2;
END LOOP;
END IF;
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(SQLCODE ||': '||SQLERRM);
END;
COMMIT;
END;
谢谢!