1

我正在尝试使用 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;

谢谢!

4

0 回答 0