我在Oracle中编写了以下脚本,该脚本在一个表中插入了数千行,并使用这些行产生的自动生成的ID并将其用于其他插入。
该脚本可以按预期工作,但问题是需要花费一些时间才能完成。 以下是当前每个表的内容的一些详细信息:
使用这些卷,脚本大约需要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;
/
答案 0 :(得分: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;
/
我敲了一个simple test case,以表明生成的序列号已为每个源行的每个目标表重复使用。
如果表之间有外键,则可能需要在插入之前将其禁用,然后再重新启用它们。
通常不建议在INSERT ALL中使用序列(例如https://asktom.oracle.com/pls/apex/f?p=100:11:0::::P11_QUESTION_ID:9532591900346482312),因此您最好创建一个表以容纳select语句的内容以及序列号,然后在表中使用该新表。全部插入。
答案 1 :(得分:-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;
/