【问题标题】:INSERT INTO SELECT vs. INSERT from Cursor in PL/SQLINSERT INTO SELECT 与 INSERT from Cursor in PL/SQL
【发布时间】:2018-02-06 11:45:40
【问题描述】:

所以我有一个我正在工作的项目,我注意到很多人使用 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 包。我的问题是,这通常是“首选”方法,什么时候?我通常选择游标方法,因为它在异常处理方面给了我更多的灵活性。但是,我可以看到插入大量记录时这可能是一个性能问题。

【问题讨论】:

  • 第一个效率更高。当您可以编写 SQL 查询来完成任务时,您必须使用游标
  • @JoeTaras 我想你的意思是说“不应该”而不是“必须”?
  • @TonyAndrews:是的,重要的是尝试创建正确的 SQL 查询。作为替代解决方案的游标(因为效率低于查询)

标签: oracle plsql plsqldeveloper


【解决方案1】:

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

SQL 和 PLSQL 之间的每次切换以及每次 FETCH 的成本都很高。

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

还有其他优点,但这是这两种方法之间的主要 PLSQL 区别。

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

      如果您确实需要游标处理的灵活性但需要更好的性能,则可以使用第三个中间选项 - 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 ;
      

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

      【讨论】:

        猜你喜欢
        • 2012-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-08-02
        • 2020-07-13
        • 2011-01-29
        • 1970-01-01
        相关资源
        最近更新 更多