Oracle 11g - 插入多行的最有效方式

Posted

技术标签:

【中文标题】Oracle 11g - 插入多行的最有效方式【英文标题】:Oracle 11g - most efficient way of inserting multiple rows 【发布时间】:2013-08-07 04:00:30 【问题描述】:

我有一个在 WAN 上运行缓慢的应用程序 - 我们认为原因是多次插入到表中。我目前正在寻找更有效的方法来同时插入多行。

我找到了这个方法:

INSERT ALL
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (100,20)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (21,2)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (321,10)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (22,13)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (14,121)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (11,112)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (112,23)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (132,2323)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (121,34)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (24333,333)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (1232,3434)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (4554,3434)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (3434,211)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (3434,1233)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (12,22)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (356,233)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (9347,23)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (8904,245)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (342,4545)
  INTO MULTI_INSERT(VAL_1, VAL_2) VALUES (453,233)
SELECT 1 FROM DUAL;

我想知道的是:上述方法实际上是否比仅执行 20 "INSERT INTO MY_TABLE (1,1);" 更有效?还有其他方法吗?

【问题讨论】:

桌子上有触发器吗? 嗨,Harshit - 不,桌子上没有触发器 大概你的现实生活用例超过 20 行?而不是硬编码的值? @APC,是的,没错,该表是一个审计跟踪,一次插入大约 100 行,全部由当时的应用程序生成,因此没有硬编码值。跨度> 您是否调查过为什么现有的插入很慢? 100 行并不多,您应该能够在几乎任何时间内运行 100 条插入语句。这表明您还有其他问题:I/O 或 CPU 争用,或者某些描述的锁定?您应该花一些时间诊断当前代码的行为,而不是猜测可能是错误问题的解决方案。 【参考方案1】:

您可以尝试direct path insert 来加快操作速度,但是对于 100 条记录,常规路径插入必须足够快,而且似乎问题在于从大量来源插入日志时表锁定。

要指示 Oracle 使用直接路径插入,您必须根据插入语句语法指定 APPEND 或 APPEND_VALUES 提示。例如

insert /*+ APPEND */ 
into multi_insert(val_1, val_2)
select * from (
  select 100,    20 from dual union all
  select 21,      2 from dual union all
  select 321,    10 from dual union all
  select 22,     13 from dual union all
  select 14,    121 from dual union all
  select 11,    112 from dual union all
  select 112,    23 from dual union all
  select 132,  2323 from dual union all
  select 121,    34 from dual union all
  select 24333, 333 from dual union all
  select 1232, 3434 from dual union all
  select 4554, 3434 from dual union all
  select 3434,  211 from dual union all
  select 3434, 1233 from dual union all
  select 12,     22 from dual union all
  select 356,   233 from dual union all
  select 9347,   23 from dual union all
  select 8904,  245 from dual union all
  select 342,  4545 from dual union all
  select 453,   233 from dual
)

如果插入语句源自 PL/SQL 代码,那么您可以使用批量插入和 forall 语句来提高性能 (SQLFiddle):

declare
  type TRowList is table of multi_insert%rowtype index by binary_integer;

  vRowList TRowList;
  vRow     multi_insert%rowtype;
begin


  vRow.val_1 := 100;
  vRow.val_2 := 20;
  vRowList(0) := vRow;

  vRow.val_1 := 21;
  vRow.val_2 := 2;
  vRowList(1) := vRow;

  vRow.val_1 := 321;
  vRow.val_2 := 10;
  vRowList(2) := vRow;

  -- ...

  forall vIdx in vRowList.first .. vRowList.last
        insert /*+ APPEND_VALUES */  -- direct path insert
        into multi_insert values vRowList(vIdx);

end;

【讨论】:

【参考方案2】:

"一个客户报告说,当应用程序运行良好时 和甲骨文在同一个局域网上,但是当他们移动甲骨文时 国外的服务器他们说程序运行很慢”

好的,现在我们正在取得进展。如果您有一个设置,其中您的一百个语句是单独的调用,它们可能会以单独的数据包发送。与 LAN 相比,通过 WAN 会很痛苦。在这种情况下,将语句从 RBAR 转换为基于 Set 的语句是否会减少传输数据包的数量是值得的。

但是,我仍然建议您在推出更改之前了解一些确凿的事实。您的客户没有可以与之交谈的网络管理员吗?或者至少你能让他们安装Wireshark 并向你发送一些报告吗?

【讨论】:

我们刚刚设法在 VPS 上设置了一个远程 Oracle 服务器并将我们的应用程序连接到它。我对其进行了wireshark捕获,发现它为每一行发送单独的数据包。我的一位同事重新编译了应用程序,这一次使用了 Direct Oracle Access(我们用来与 Oracle 通信的库)的一些特性,称为“数组 DML”。这几乎不会发送任何数据包,而且几乎是即时的。但是,我想知道这个“数组 DML”实际上是什么,因为我们有其他(非 Delphi)应用程序可能会遇到同样的问题 - 你能对此有所了解吗? 可能 DOA 使用了带有 OCI 的 APPEND_VALUES hint 的一些变体,并将数组参数绑定到 insert 语句。 AnyDac 帮助有 explanation 关于某个主题,here 是来自 Oracle 文档的一点信息。【参考方案3】:

一些RDBMS,比如mysql,现在SQL Server支持多行插入数据语法:

Insert into myTable ( c1, c2 ) values
( 1,1 ),
( 1,2 ),
... ;

(更多细节在Inserting multiple rows of data of Sql Server或inserting multirow on mysql)

但不要预言。很抱歉坏消息。更接近的方法记录在Tech on the Net。

【讨论】:

【参考方案4】:

Oracle 不支持多行插入,请使用下一个选项:

插入方法(名称)值('GET'); 插入方法(名称)值('POST');

【讨论】:

以上是关于Oracle 11g - 插入多行的最有效方式的主要内容,如果未能解决你的问题,请参考以下文章

如何在oracle 11g中使用一个INSERT语句在一列中插入多行[重复]

Oracle 11g改密码有效期

插入 5000 多个 Android 联系人的最有效方式

查询在 Oracle 11g 上有效,但在 Oracle 8i 上失败

oracle11g rman验证备份有效性

SQL Merge 语句在 Oracle 11g 中有效,但在 9i 中无效