我正在为Oracle 10g开发存储过程,并且在尝试将大约2-3k项的列表传递到过程中时,我遇到了相当沉重的性能瓶颈。这是我的代码:
TYPE ty_id_list
AS TABLE OF NUMBER(11);
----------------------------------------------------------
PROCEDURE sp_performance_test (
p_idsCollection IN schema.ty_id_list )
AS
TYPE type_numeric_table IS TABLE OF NUMBER(11) INDEX BY BINARY_INTEGER;
l_ids type_numeric_table;
data type_numeric_table;
empty type_numeric_table;
BEGIN
EXECUTE IMMEDIATE
'ALTER TABLE schema.T_TEST_TABLE NOLOGGING';
COMMIT;
SELECT COLUMN_VALUE BULK COLLECT INTO l_ids
FROM TABLE(p_idsCollection);
FOR j IN 1 .. l_ids.COUNT LOOP
data(data.count+1) := l_ids(j);
IF(MOD(data.COUNT,500) = 0 ) THEN
FORALL i IN 1 .. data.COUNT
INSERT INTO schema.T_TEST_TABLE (REF_ID, ACTIVE)
VALUES (data(i), 'Y');
data := empty;
END IF;
END LOOP;
IF(data.count IS NOT NULL) THEN
FORALL i IN 1 .. data.COUNT
INSERT INTO schema.T_TEST_TABLE (REF_ID, ACTIVE)
VALUES (data(i), 'Y');
END IF;
COMMIT;
EXECUTE IMMEDIATE
'ALTER TABLE schema.T_TEST_TABLE LOGGING';
COMMIT;
END sp_performance_test;
因此,相当大的过程似乎就是这一部分:data(data.count + 1):= l_ids(j);如果我跳过从集合中获取元素并将此行更改为data(data.count + 1):= j ;,则程序执行时间将快3-4倍(从30多秒到8- 9k项目的9s) - 但这个逻辑显然不是我想要的那个。
你们可以给我一个提示,我可以在哪里改进我的代码以获得更好的插入数据性能?如果可以做任何改进。
谢谢, Przemek
答案 0 :(得分:0)
我不遵循你的逻辑。
您接受一个集合。您将其复制到另一个集合:
SELECT COLUMN_VALUE BULK COLLECT INTO l_ids
FROM TABLE(p_idsCollection);
然后你再次复制它,循环:
FOR j IN 1 .. l_ids.COUNT LOOP
data(data.count+1) := l_ids(j);
只有在那之后你才能设法执行你的500行大块插入。批量插入p_idsCollection
会立即出现什么问题?
P.S。在'ALTER TABLE'之后你不需要提交,ddl语句会隐式发出它们。
答案 1 :(得分:0)
DDL之后的整个块可以重写为
insert into schema.T_TEST_TABLE (REF_ID, ACTIVE)
select COLUMN_VALUE, 'Y' FROM TABLE(p_idsCollection);
答案 2 :(得分:0)
您还可以在插入操作中添加提示。
将/ * +追加* /插入标签(...)值(...)
它改变了oracle的工作逻辑,它会更快地运行。