【问题标题】:Sql Server 2005 - Insert if not existsSql Server 2005 - 如果不存在则插入
【发布时间】:2011-09-01 12:36:25
【问题描述】:

互联网上有很多关于这个常见“问题”的信息。

解决方案如:

IF NOT EXISTS() BEGIN INSERT INTO (...) END

在我看来不是线程安全的,你可能会同意。

但是你能确认把exist放到一个单选的where子句中就可以解决sql引擎中最高并发的问题吗? 够了吗?

insert into Table (columns)
select column1, column2, column3
where not exists (select top 1 1 from Table where something)

应该还有添加一些更高的事务级别或 这可以在默认的上执行吗:已提交?

这会在未提交的级别下工作吗?

谢谢!

//稍后添加

我可以假设两个 sql' 都是正确的吗:

1) 设置事务隔离级别可重复读

   IF NOT EXISTS() BEGIN INSERT INTO (...) END

2) 设置事务隔离级别可重复读

insert into Table (columns)
select column1, column2, column3
where not exists (select top 1 1 from Table where something)

【问题讨论】:

  • 不,它在 readcommitted 或 uncommitted 级别都不起作用。您将需要一些额外的锁定提示。 Only inserting a row if it's not already there 的可能重复项
  • 您不需要“帮助”exists 子句——它们足够聪明,可以在看到 1 行后完成。你可以只做EXISTS (SELECT * FROM...,它会做正确的事。
  • 它会做正确的事情,但在并发的情况下,它不够线程安全,并且在高负载下可能会发生主要违规错误。所以根据@Martin的链接,应该添加可重复读隔离事务。
  • @Paul - 我的意思是你不需要在 exists 子句中使用 select top 1... - 我没有评论代码的其余部分。
  • @Damien_The_Unbeliever Aaa 好的,很抱歉造成误解。我一直认为写:“top 1 1”不会使服务器获取列的值..

标签: sql-server transactions insert exists


【解决方案1】:

使用 TRY/CATCH 可以避免额外的读取

BEGIN TRY
   INSERT etc
END TRY
BEGIN CATCH
    IF ERROR_NUMBER() <> 2627
      RAISERROR etc
END CATCH
  • A NOT EXISTS 将读取表,无论是在 IF 还是 WHERE 中
  • INSERT 需要读取以检查唯一性

如果您可以丢弃重复项,这是一种高度可扩展的技术

链接:

【讨论】:

  • 好吧,但是如果我应该插入或更新然后:我可以这样做:如果 error_number() = 2627 开始更新...结束?
  • @Paul:然后查看我的最后一个链接以处理更新
  • 是否可以在开始捕获块中引发默认错误?还是我必须明确获取 error_number 和消息以满足 raiserror 参数?
  • @Paul:您必须阅读 ERROR_NUMBER() 和 ERROR_MESSAGE() 等并构建自己的消息。 Example。但是,这个数字变成了 50000。在下一个版本中添加了重新抛出相同错误的能力:THROW
【解决方案2】:

回答更新后的问题repeatable read 仍然不够。

这是您需要的 holdlock / serializable 级别。

您试图阻止 phantoms(在第一次读取时没有行符合条件,因此 NOT EXISTS 返回 true,但随后并发事务插入符合它的行)

【讨论】:

  • 看来我在写sql语句的时候会开始偏执:)
  • @Paul - serializable 也会给你带来死锁的风险,这可以通过UPDLOCK, HOLDLOCK 来避免。不过我自己会使用TRY...CATCH
猜你喜欢
  • 2011-07-01
  • 2018-09-17
  • 2015-07-06
  • 2014-01-25
  • 2020-08-07
  • 2016-11-07
  • 2020-04-22
  • 1970-01-01
相关资源
最近更新 更多