在Oracle中更新vs Merge以获取不是批量记录集的记录列表?性能?

时间:2013-10-03 05:16:37

标签: sql database oracle oracle-sqldeveloper

目前我的项目中有很多更新语句。我正在做的是传递一个列表 在DataAccess层中循环它并更新数据库

假设我有一个记录列表包含Comment,userID和ID ..我正在基于循环中的ID更新...有没有更好的方法来做...

我可以使用合并声明吗?它会提高性能吗?究竟是什么区别?

UPDATE RecordTable
SET
COMMENT=:COMMENT,
MODIFIEDDate = SYSTIMESTAMP, 
UserID = :UserID 
WHERE ID = :ID

3 个答案:

答案 0 :(得分:4)

合并将更好然后更新,原因很简单,一次执行一行更新会导致大量不必要的上下文切换和索引/表访问。 Oracle在批量生产中运营得更好。

为了能够在此处使用合并声明,您必须使用IDCOMMENTUSERID创建一个中间表。

只有在您可以执行合并

之后
merge into RecordTable a using TEMP_recordtable b 
on (a.id = b.id) 
when matched then update set 
 a.COMMENT=b.COMMENT ,
 a.MODIFIEDDate = SYSTIMESTAMP, 
 a.UserID = b.UserID

编辑:在没有临时表的情况下进行更新

演示表

SQL> create table m1 (id number , name varchar2(30) , updated date);
Table created.
SQL> insert into m1 values (1 , 'Haki', sysdate);
1 row created.
SQL> insert into m1 values (3 , 'Simon', sysdate);
1 row created.
SQL> commit;
SQL> select * from m1;

        ID NAME                           UPDATED
---------- ------------------------------ -------------------
         1 Haki                           03/10/2013 09:39:37
         3 Simon                          03/10/2013 09:38:17

如果要在sql中使用集合,则需要在db

中声明它们
SQL> create type rec as object (id number , name varchar2(10))
  2  /
Type created.

SQL> create type rec_arr as table of rec;
  2  /
Type created.

现在我们创建列表并将其合并到我们的表

SQL> ed
Wrote file afiedt.buf

  1  declare
  2  myarr rec_arr := rec_arr( rec (1 , 'Haki') , rec (2 , 'Raul'));
  3  begin
  4     merge into m1 using table(myarr) b on (m1.id = b.id)
  5     when matched then update set
  6             m1.name = b.name ,
  7             m1.updated = sysdate
  8     when not matched then insert (id , name , updated)
  9     values (b.id , b.name , sysdate);
 10* end;
SQL> /

PL/SQL procedure successfully completed.

SQL> select * from m1;

        ID NAME                           UPDATED
---------- ------------------------------ -------------------
         1 Haki                           03/10/2013 09:40:16
         3 Simon                          03/10/2013 09:38:17
         2 Raul                           03/10/2013 09:40:16

3 rows selected.

如您所见,现有记录已更新,新记录已插入。

答案 1 :(得分:3)

您可以像执行合并一样轻松地批量执行更新。

将所需的更新值加载到全局临时表中,并确保在连接键上存在主要或唯一键约束,并且要更新表。您针对两个表的连接运行更新,类似于:

update (
  select t.pk,
         t.old_value,
         s.new_value
  from   target_table t
  join   source_table s on (s.pk = t.some_column))
set old_value = new_value.

只要内联视图是“密钥保留”,更新就会像合并一样快。

http://docs.oracle.com/cd/E11882_01/server.112/e41084/statements_10008.htm

同样,您可以对密钥保留的视图或内嵌视图执行删除。

答案 2 :(得分:1)

正如其他人所指出的那样,上下文切换对性能来说太可怕了。但请记住,在减少上下文切换时,收益递减规律会很快发挥作用。一次填充10行会使它们减少90%,填充100行会使它们减少99%等等。为了获得大部分性能提升,您只需要组合相对较少的语句。

许多环境都有自动执行此操作的功能。例如PL / SQL forall或JDBC批处理。如果那些不可用,你 可以通过在较大的语句中手动将数据集分组在一起来实现此目的。例如:

merge into RecordTable
using
(
    select :id1 id, :comment1 comment, :userID1 userID from dual union all
    select :id2 id, :comment2 comment, :userID2 userID from dual union all
    ...
    select :id10 id, :comment10 comment, :userID10 userID from dual
) new_data
on RecordTable.id = new_data.id
when matched then update set
    RecordTable.comment = new_data.comment,
    RecordTable.modfifiedDate = systimestamp,
    RecordTable.UserId = new_data.userID;

对于剩余的行,请使用null作为ID,这些记录与任何内容都不匹配。

如果您的问题仅与mergeupdate有关,则最显着的性能差异是merge可以支持散列连接,而update则不能。但这不重要。