在PL / SQL中从Cursor INSERT INTO SELECT与INSERT

时间:2018-02-02 15:11:37

标签: oracle plsql plsqldeveloper

所以我有这个项目,我正在工作,我注意到很多人使用INSERT INTO SELECT方法:

INSERT INTO candy_tbl (candy_name, 
                       candy_type, 
                       candy_qty) 
SELECT food_name, 
       food_type, 
       food_qty 
       FROM food_tbl WHERE food_type = 'C';

但是,我使用以下游标方法:

FOR rec IN ( SELECT 
             food_name, 
             food_type, 
             food_qty 
             FROM food_tbl WHERE food_type = 'C') 
LOOP INSERT INTO candy_tbl(candy_name, 
                           candy_type, 
                           candy_qty) 
                    VALUES(rec.food_name,
                           rec.food_type, 
                           rec.food_qty) 
END LOOP;

这将进入PL / SQL包。我的问题是,这通常是首选的'方法何时?我通常选择游标方法,因为它为异常处理提供了更多的灵活性。但是,在插入大量记录时,我可以看到它可能是一个性能问题。

4 个答案:

答案 0 :(得分:1)

FOR LOOP需要从CURSOR获取每一行。循环中的INSERT将由1进行.PLSQL在PLSQL引擎中运行,SQL在SQL引擎中运行,因此FOR LOOP: - 在PLSQL引擎中运行 - 将查询发送到SQL引擎以执行查询并打开游标,然后切换回PLSQL引擎 - 每个循环从CURSOR执行FETCH,然后执行INSERT意义返回SQL引擎然后返回到PLSQL引擎

SQL和PLSQL之间的每次切换以及每个FETCH都很昂贵。

INSERT INTO SELECT将被发送到SQL引擎一次并在那里运行直到完成然后再回到PLSQL。

存在其他优点,但这是两种方法之间主要的PLSQL差异。

答案 1 :(得分:0)

Insert as select具有默认sql的优点,因此,使用这种指令的PL / SQL并不完全是人们常见的。 使用游标比选择插入更灵活,通常更像verborragic。 我个人建议您尽可能使用Insert作为select,这样可以避免为项目增加复杂性,普通用户阅读代码会更简单。请记住,许多知道SQL但很少知道PL / SQL的人。

在性能方面,insert as select似乎更具性能,但我从来没有见过一个和另一个之间有任何显着差异。

答案 2 :(得分:0)

第一个更快,因为它基本上是单个事务,也就是基于集合的处理。

后者按行进行操作,对于非常大的表格,性能会有很大差异。

答案 3 :(得分:0)

如果您确实需要游标处理的灵活性但性能更好,则可以使用第三个中间选项 - BULK COLLECT和FORALL以及保存例外选项。然而,权衡更多是代码复杂性。以下是基本结构。

declare
    exception error_in_forall ; 
    pragma exception_init (error_in_forall, -24381);

    cursor c_select is ( select ... ) ;
    type   c_array_type table of c_select%rowtype;     
    v_select_data  c_array_type ; 

begin 
    open c_select; 
    loop
        fetch c_select
         bulk collect 
         into v_select_data; 
        forall rdata in v_select_data.first .. v_select_data.last save exceptions
            insert into ( ... ) values (v_select_data(rdata).column ... ) ;    
exceptions 
    when error_in_forall then
        <Process Oracle generated bulk error collection > 
end ;

如果在执行Insert期间发生任何错误,则完成后,异常将触发一次。 Oracle构建了一个SQL%BULK_EXCEPTIONS集合,其中包含索引值和每个的错误代码。有关详细信息,请参阅适用于您的版本的PL / SQL语言参考。