我们一直使用临时表将中间结果存储在pl / sql存储过程中。任何人都可以判断通过pl / sql进行批量收集插入与普通SQL插入之间是否存在性能差异。
插入[表名] [选择查询返回大量数据]
或
[选择查询返回大量数据]的光标
打开游标
将游标批量收集到集合中
使用FORALL执行插入
以上哪两个选项最好插入大量的临时数据?
答案 0 :(得分:7)
您的问题的一些实验数据(Oracle 9.2)
批量收集
DECLARE
TYPE t_number_table IS TABLE OF NUMBER;
v_tab t_number_table;
BEGIN
SELECT ROWNUM
BULK COLLECT INTO v_tab
FROM dual
CONNECT BY LEVEL < 100000;
FORALL i IN 1..v_tab.COUNT
INSERT INTO test VALUES (v_tab(i));
END;
/
-- 2.6 sec
插入强>
-- test table
CREATE global TEMPORARY TABLE test (id number)
ON COMMIT preserve ROWS;
BEGIN
INSERT INTO test
SELECT ROWNUM FROM dual
CONNECT BY LEVEL < 100000;
END;
/
-- 1.4 sec
直接路径插入 http://download.oracle.com/docs/cd/B10500_01/server.920/a96524/c21dlins.htm
BEGIN
INSERT /*+ append */ INTO test
SELECT ROWNUM FROM dual
CONNECT BY LEVEL < 100000;
END;
/
-- 1.2 sec
答案 1 :(得分:3)
这取决于您为填充中间结果所做的工作的性质。如果可以在INSERT的SELECT语句中相对简单地完成工作,那通常会表现得更好。
但是,如果您有一些复杂的中间逻辑,从代码维护的角度来看,使用批量收集/绑定批量获取和插入数据可能更容易。在某些情况下甚至可能更快。
需要非常仔细地注意一点: INSERT INTO x SELECT ...
使用的查询计划有时与查询自行运行时使用的查询计划完全不同(例如,在PL / SQL中)显式游标)。在比较性能时,您需要考虑到这一点。
答案 2 :(得分:2)
插入选择必须更快。首先省略将数据存储在集合中的开销。
答案 3 :(得分:2)
作为选择插入,所有时间都胜出,而且即使是适度的数据集也存在显着差异。
那就是说。之前的评论是关于中间计算的复杂性。我可以想到三种相关的情况。
1)如果计算需要在Oracle数据库之外进行,那么显然只需一个简单的插入作为select就行了。
2)如果解决方案需要使用PLSQL函数调用,那么上下文切换可能会破坏您的查询,并且plsql调用plsql函数可能会有更好的结果。 PLSQl被用来调用SQL但不是相反。因此从SQL调用PLSQL很昂贵。
3)如果计算使得sql代码很难阅读,那么即使它可能更慢,plsql批量收集解决方案可能因其他原因更好。
祝你好运。答案 4 :(得分:0)
当我们显式声明游标时,oracle将在我们的RAM中分配一个私有SQL工作区。当您有select语句返回多行时,将从表或视图复制到私有SQL工作区作为ACTIVE SET。其大小是符合搜索条件的行数。一旦打开游标,您的指针将被放置在ACTIVE SET的第一行。在这里你可以执行DML。例如,如果您执行某些更新操作。它将更新工作区中行的任何更改,而不是直接更新表中的行。因此,每次我们需要更新时都不会使用该表。它一次取到工作区,然后在执行操作后,对所有操作进行一次更新。这减少了数据库和用户之间的输入/输出数据传输。
答案 5 :(得分:-3)
我建议使用PL \ SQL显式游标,你只是在为光标分配的私有工作空间执行任何DML操作。这不会在高峰时段达到数据库服务器性能