3

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

假设我有一个包含评论、用户 ID 和 ID 的记录列表..我正在循环中根据 ID 进行更新...有没有更好的方法来做到这一点..

我可以使用合并语句吗?它会提高性能吗?确切的区别是什么?

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

3 回答 3

4

合并会比更新更好,原因很简单,一次执行更新一行会导致大量不必要的上下文切换和索引/表访问。甲骨文在批量方面运作得更好。

为了能够在此处使用合并语句,您必须使用IDCOMMENT和创建一个中间表USERID

只有在您可以执行合并之后

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.

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

于 2013-10-03T05:41:02.123 回答
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

同样,您可以对保留键的视图或内联视图执行删除。

于 2013-10-03T09:31:44.847 回答
1

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

许多环境具有自动执行此操作的功能。例如 PL/SQLforall或 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 并且这些记录将不匹配任何内容。

如果您的问题只是关于mergevs. update,那么最显着的性能差异是merge可以支持散列连接而update不能。但这并不重要。

于 2013-10-04T04:50:41.530 回答