查询性能差异pl / sql forall insert和普通SQL插入

时间:2010-04-20 05:28:15

标签: sql oracle plsql performance

我们一直使用临时表将中间结果存储在pl / sql存储过程中。任何人都可以判断通过pl / sql进行批量收集插入与普通SQL插入之间是否存在性能差异。

插入[表名] [选择查询返回大量数据]

[选择查询返回大量数据]的光标

打开游标

将游标批量收集到集合中

使用FORALL执行插入

以上哪两个选项最好插入大量的临时数据?

6 个答案:

答案 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)

asktomhome成名的Tom Kyte更坚定地回答了这个问题。如果您愿意进行一些搜索,您可以找到问题及其响应,其中包含详细的测试结果和解释。他展示了plsql游标与plsql批量收集,包括定期提交的影响,而sql insert as select。

作为选择插入,所有时间都胜出,而且即使是适度的数据集也存在显着差异。

那就是说。之前的评论是关于中间计算的复杂性。我可以想到三种相关的情况。

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操作。这不会在高峰时段达到数据库服务器性能