0

我在 Oracle 中编写了下面的脚本,该脚本在表中插入数千行,并使用这些行产生的自动生成的 id 并在其他插入中使用它。

该脚本按预期工作,但问题是它需要时间才能完成。以下是当前每个表的内容的一些细节:

  • table_0 包含 16000+ 行
  • table_1 包含 4000+ 行

使用这些卷,脚本大约需要 15 到 20 秒。问题是我打算使用类似的查询来处理数百万行。

这是脚本调用的函数的代码:

create or replace FUNCTION get_id (name1 IN varchar2) RETURN INTEGER
as res_id INTEGER;
begin

select id  into res_id from table_1 where node_type='type1' and name = 
 name1;

return res_id;
end;
/

这是脚本本身:

DECLARE

  TYPE rt IS RECORD (text1 varchar2(20),text2 varchar(20));

  TYPE texts_tab IS TABLE OF rt;
  TYPE ids_tab   IS TABLE OF table_1.id%TYPE;
  p_texts texts_tab;
  p_ids   ids_tab;
  id_2 integer;
  CURSOR c IS
    SELECT DISTINCT text1,text2 FROM table_0 order by text1,text2;
BEGIN
select FUNC1('type2') into id_2 from dual;
  OPEN c;
  LOOP
    FETCH c BULK COLLECT INTO p_texts LIMIT 1000;

    FORALL i IN 1 .. p_texts.COUNT
       INSERT INTO table_2(object_id,object_type,parent_id)
        VALUES (SEQ_ID.NEXTVAL, id_2 ,get_id(p_texts(i).text1) ,0,0)
        RETURNING object_id BULK COLLECT INTO p_ids;

    FORALL i IN 1 .. p_ids.COUNT
      insert into table_3 (object_id,field2)
        VALUES ( p_ids(i), p_texts(i).text2 );

     FORALL i IN 1 .. p_ids.COUNT   
        insert into table_1 (node_type,text1,id)
    VALUES('type2', p_texts(i).text1 , p_ids(i));

    EXIT WHEN c%NOTFOUND;
  END LOOP;
  CLOSE c;
  COMMIT;
END;
/
4

2 回答 2

2

我认为你可以更简单地使用 INSERT ALL 来做到这一点,例如:

DECLARE
  id_2    INTEGER;
BEGIN
  id_2 := func1('type2');

  INSERT ALL
    INTO table_2 (object_id, object_type, parent_id) VALUES (seq_id.nextval, id_2, res_id)
    INTO table_3 (object_id, field2) VALUES (seq_id.nextval, text2)
    INTO table_1 (node_type, text1, ID) VALUES ('type2', text1, seq_id.nextval)
  SELECT t0.text1,
         t0.text2,
         t1.id AS res_id
  FROM   (SELECT DISTINCT text1,
                          text2
          FROM   table_0) t0
         LEFT OUTER JOIN table_1 t1 ON t0.text1 = t1.name AND t1.node_type = 'type1';

  COMMIT;
END;
/

我敲了一个简单的测试用例来显示生成的序列号被重复用于每个源行的每个目标表。

如果表之间有外键,您可能需要在插入之前禁用它们并在之后重新启用它们。

注意通常不建议在 INSERT ALL 中使用序列(例如https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9532591900346482312),所以你可以这样做最好创建一个表来保存 select 语句的内容以及序列号,然后在全部插入时使用该新表。

于 2019-06-11T10:56:41.537 回答
-1

我已删除函数调用并将该函数结果合并到直接游标查询中。

实际上,为游标的每一行调用函数会降低性能,这就是我的想法。

您能否尝试以下代码并分享结果:

DECLARE
    TYPE RT IS RECORD (
        TEXT1     VARCHAR2(20),
        TEXT2     VARCHAR(20),
        ID        VARCHAR2(20) -- SET IT ACCORDING TO YOUR DATA TYPE AND SIZE
    );
    TYPE TEXTS_TAB IS
        TABLE OF RT;
    TYPE IDS_TAB IS
        TABLE OF TABLE_1.ID%TYPE;
    P_TEXTS   TEXTS_TAB;
    P_IDS     IDS_TAB;
    ID_2      INTEGER;
    -- CHANGED THIS CURSOR TO REMOVE FUNCTION
    CURSOR C IS
    SELECT DISTINCT
        T0.TEXT1,
        T0.TEXT2,
        T1.ID
    FROM
        TABLE_0 T0,
        TABLE_1 T1
    WHERE
        T1.NODE_TYPE = 'type1'
        AND T1.NAME = T0.TEXT1
    ORDER BY
        TEXT1,
        TEXT2;

BEGIN
    SELECT
        FUNC1('type2')
    INTO ID_2
    FROM
        DUAL;

    OPEN C;
    LOOP
        FETCH C BULK COLLECT INTO P_TEXTS LIMIT 1000;
        FORALL I IN 1..P_TEXTS.COUNT
            INSERT INTO TABLE_2 (
                OBJECT_ID,
                OBJECT_TYPE,
                PARENT_ID
            ) VALUES (
                SEQ_ID.NEXTVAL,
                ID_2,
                P_TEXTS(I).ID, -- ADDED DIRECTLY ID INSTEAD OF FUNCTION CALL
                0,
                0
            ) RETURNING OBJECT_ID BULK COLLECT INTO P_IDS;

        FORALL I IN 1..P_IDS.COUNT
            INSERT INTO TABLE_3 (
                OBJECT_ID,
                FIELD2
            ) VALUES (
                P_IDS(I),
                P_TEXTS(I).TEXT2
            );

        FORALL I IN 1..P_IDS.COUNT
            INSERT INTO TABLE_1 (
                NODE_TYPE,
                TEXT1,
                ID
            ) VALUES (
                'type2',
                P_TEXTS(I).TEXT1,
                P_IDS(I)
            );

        EXIT WHEN C%NOTFOUND;
    END LOOP;

    CLOSE C;
    COMMIT;
END;
/
于 2019-06-11T08:14:26.447 回答