T-SQL插入或更新

Mar*_*kus 33 t-sql sql-server insert-update

我有一个关于SQL Server性能的问题.

假设我有一个表persons有以下栏目:id,name,surname.

现在,我想在此表中插入一个新行.规则如下:

  1. 如果id表中没有,则插入行.

  2. 如果id存在,则更新.

我这里有两个解决方案:

第一:

update persons
  set id=@p_id, name=@p_name, surname=@p_surname
where id=@p_id
if @@ROWCOUNT = 0 
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)
Run Code Online (Sandbox Code Playgroud)

第二:

if exists (select id from persons where id = @p_id)
  update persons
    set id=@p_id, name=@p_name, surname=@p_surname
  where id=@p_id
else
  insert into persons(id, name, surname)
  values (@p_id, @p_name, @p_surname)
Run Code Online (Sandbox Code Playgroud)

什么是更好的方法?看起来在第二个选择中,要更新一行,它必须被搜索两次,而在第一个选项中 - 只需一次.这个问题还有其他解决方案吗?我正在使用MS SQL 2000.

Luc*_*ero 12

选项1似乎很好.但是,如果您使用的是SQL Server 2008,则还可以使用MERGE,这可能对此类UPSERT任务有效.

请注意,您可能希望对此类任务使用显式事务和XACT_ABORT选项,以便在出现问题或并发更改时保持事务一致性.

  • @z0r 您始终可以用 VALUES 替换(只读)表,使用以下内容代替表引用: `(VALUES (1,'a'),(2,'b')) AS v(i,s )` (2认同)

dan*_*dan 9

两者都工作正常,但我通常使用选项2(pre-mssql 2008),因为它读得更清楚一点.我不会在这里强调性能......如果它成为问题,你可以NOLOCKexists条款中使用.虽然在你开始在任何地方使用NOLOCK之前,请确保你已经涵盖了所有的基础(索引和大图片架构的东西).如果您知道您将多次更新每个项目,那么可能需要考虑选项1.

选项3是不使用破坏性更新.这需要更多的工作,但基本上每次数据更改时都会插入一个新行(从不更新或从表中删除),并且有一个选择所有最新行的视图.如果您希望表包含其以前所有状态的历史记录,那么它很有用,但它也可能过度.


小智 6

您可以使用 @@RowCount 来查看更新是否执行了任何操作。就像是:

    UPDATE MyTable
       SET SomeData = 'Some Data' WHERE ID = 1
    IF @@ROWCOUNT = 0
      BEGIN
        INSERT MyTable
        SELECT 1, 'Some Data'       
      END
Run Code Online (Sandbox Code Playgroud)


小智 5

我倾向于使用选项 1。如果表中有记录,则保存一次搜索。如果没有,你不会失去任何东西。此外,在第二个选项中,您可能会遇到与锁不兼容相关的有趣的锁定和死锁问题。我的博客上还有更多信息:

http://sqlblogcasts.com/blogs/piotr_rodak/archive/2010/01/04/updlock-holdlock-and-deadlocks.aspx