【问题标题】:Inserting multiple rows into Oracle在 Oracle 中插入多行
【发布时间】:2010-10-27 09:21:48
【问题描述】:

discussion关于将多行插入到Oracle中的两种方法进行了演示:

第一:

insert into pager (PAG_ID,PAG_PARENT,PAG_NAME,PAG_ACTIVE)
          select 8000,0,'Multi 8000',1 from dual
union all select 8001,0,'Multi 8001',1 from dual

第二:

INSERT ALL
   INTO t (col1, col2, col3) VALUES ('val1_1', 'val1_2', 'val1_3')
   INTO t (col1, col2, col3) VALUES ('val2_1', 'val2_2', 'val2_3')
   INTO t (col1, col2, col3) VALUES ('val3_1', 'val3_2', 'val3_3')
   .
   .
   .
SELECT 1 FROM DUAL;

有人可以争论使用其中一种优于另一种吗?

附:我自己没有做任何研究(甚至是解释计划),所以任何信息或意见都将不胜感激。

谢谢。

【问题讨论】:

    标签: sql oracle insert


    【解决方案1】:

    从性能的角度来看,这些查询是相同的。

    UNION ALL 不会影响性能,因为 Oracle 仅在需要时估计 UNION'ed 查询,它不会先缓存结果。

    SELECT 语法在这个意义上更加灵活,如果您想更改某些内容,您可以更轻松地操作 SELECT 查询。

    例如,这个查询:

    insert into pager (PAG_ID,PAG_PARENT,PAG_NAME,PAG_ACTIVE)
              select 8000,0,'Multi 8000',1 from dual
    union all select 8001,0,'Multi 8001',1 from dual
    

    可以改写为

    INSERT
    INTO    pager (PAG_ID,PAG_PARENT,PAG_NAME,PAG_ACTIVE)
    SELECT  7999 + level, 0, 'Multi ' || 7999 + level, 1
    FROM    dual
    CONNECT BY
            level <= 2
    

    通过将2 替换为适当的数字,您可以获得任意数量的行。

    INSERT ALL 的情况下,您必须复制目标表描述,如果您需要40 行,则可读性较差。

    【讨论】:

    • 请注意,使用SOME_SEQUENCE.NEXTVAL 作为值会导致 Oracle 错误 ORA-02287: sequence number not allowed here (Oracle 11g)。此处描述了一种解决方法:orafaq.com/forum/t/54217/2 - 尝试INSERT INTO ... SELECT SOME_SEQUENCE.NEXTVAL, T.* FROM (SELECT ... UNION ALL SELECT ...) T
    【解决方案2】:

    INSERT ALL 方法在向表中插入更多行时存在问题。

    我最近想用一条 SQL 语句将 1130 行插入到一个表中。当我尝试使用INSERT ALL 方法执行此操作时,出现以下错误:

    ORA-24335 - 不能支持超过 1000 列

    当我使用INSERT INTO .. UNION ALL .. 方法时,一切都很好。

    顺便说一句。在找到这个讨论之前,我不知道 UNION ALL 方法:)

    【讨论】:

      【解决方案3】:

      我怀疑解决方案 1 是一种有效的 hack,并且可能比 Insert ALL 的设计替代方案效率低。

      Insert all 真的是为您设计的,因为您可以通过选择将许多行插入到多个表中,例如:

      Insert ALL
      into 
        t1 (c1, c2) values (q1, q2)
        t2 (x1, x2) values (q1, q3)
      select q1, q2, q3 from t3 
      

      如果您想加载数千行并且它们还没有在数据库中,我认为这不是最好的方法 - 如果您的数据在文件中,您想查看 External Tables 或 SQL Loader 以有效地为您插入行。

      【讨论】:

        【解决方案4】:

        我尝试了一些测试,更快的解决方案应该是

        insert into pager (PAG_ID,PAG_PARENT,PAG_NAME,PAG_ACTIVE)
                  select 8000,0,'Multi 8000',1 from dual
        union all select 8001,0,'Multi 8001',1 from dual
        

        在 300 400 行之间进行缓冲(我尝试使用 odbc,此值可能取决于其配置)

        【讨论】:

          【解决方案5】:

          使用UNION ALL 的语句理论上有一个小的性能劣势,因为它必须在插入发生之前合并所有语句的结果。 INSERT ALL 没有这个缺点,因为最终结果已经可以逐行处理了。

          但实际上,Oracle 内部的优化器应该可以忽略不计,这取决于您选择哪种方式。

          在我自己看来,INSERT ALL 是两者中更好的可读性,而 UNION ALL 变体是在自动生成此类插入时占用更少空间的变体。

          【讨论】:

          • 同意结论,但是: Nitpick:这些 INSERT 语句不返回任何值,因此说“在插入发生之前”或“逐行”发生任何事情是没有意义的。无论如何,他使用的是 UNION ALL,所以排序没有问题,如果这是你的想法的话。
          • 一个快速的“解释计划”显示带有 4 行 int SCOTT.EMP 的 INSERT ALL 的成本为 2(1 个多表插入,双选中只有 CPU 成本),而UNION ALL 变体的成本为 8(每个 SELECT 导致另一个 2)。它不是排序,而是结果的组合和导致成本的单个(至少 FAST DUAL)选择。
          【解决方案6】:

          如果您有超过 1000 条的插入语句,则将所有插入语句放在一个 .sql 文件中,然后在 Toad 或 SQL Developer 中打开该文件,然后执行。将插入所有记录。

          【讨论】:

          • OP 想知道他提到的其中一种方法是否优于另一种方法,而不是关于如何/在何处执行 SQL。
          【解决方案7】:

          你应该考虑数组插入。

          • 简单的 SQL
          • 需要一些客户端编码来设置数组参数

          如果需要批量完成数百次插入,这是最小化网络流量的方法。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2012-09-26
            • 1970-01-01
            相关资源
            最近更新 更多