【问题标题】:Atomicity of INSERT with subquery带有子查询的 INSERT 的原子性
【发布时间】:2012-09-12 22:59:53
【问题描述】:

假设

CREATE TABLE TableA
(
    IntColumn INT NOT NULL PRIMARY KEY
)
INSERT INTO TableA VALUES (0)

以下是原子的吗?即,如果多个应用程序线程执行以下操作,我是否有最终违反 PK 的风险?

INSERT INTO TableA
VALUES ((SELECT MAX(IntColumn) FROM TableA) + 1)

你能指出任何关于此的文档吗?我的 google-fu 失败了...

[我知道自动递增的列,但这对于我实际做的事情来说还不够。]

【问题讨论】:

  • 下载 Adam Machanic 的免费 SQL Query Stress 实用程序,让它运行 10、20、50、100 个并发客户端,看看是否有任何重复。如果你这样做,让它运行,例如同时进行 20 次迭代和 20 个客户端 - 我几乎可以保证您会看到主键违规,这表明您正在得到重复。此代码不安全。
  • 很棒的工具,感谢您的启发!

标签: sql-server tsql sql-server-2012


【解决方案1】:

This answer 显示所需的锁定提示:

INSERT INTO TableA
WITH (TABLOCKX,HOLDLOCK) -- added
VALUES ((SELECT MAX(IntColumn) FROM TableA) + 1)

Adam's utility 中尝试过,它正在工作。

【讨论】:

  • 它有效 - 但您需要注意,在整个表上放置一个排他锁,您会严重限制并发性,从而限制性能/吞吐量。这就是为什么使用INT IDENTITY 实际上是这种情况的最佳解决方案......
  • 明白。但我不能使用INT IDENTITY,因为在我的实际应用程序中IntColumn 实际上并不是主键——它是某个子集 行的唯一索引,每个子集开始编号从 0 开始(因此有重复)。考虑到这在写完之后听起来奇怪,也许我会重新考虑一下设计。
  • 听起来您需要另一列来定义您的子集(可能使用包含两列的 PK)
【解决方案2】:

您使用 SQL 2012 标记了这个问题。如果这是您的环境,您可以使用新的序列功能:http://msdn.microsoft.com/en-us/library/ff878091.aspxhttp://msdn.microsoft.com/en-us/library/ff878370.aspx

【讨论】:

  • 感谢@Sebastian - 这确实是我最终所做的。
猜你喜欢
  • 2016-10-10
  • 1970-01-01
  • 1970-01-01
  • 2018-09-16
  • 1970-01-01
  • 2013-07-09
  • 2020-06-08
  • 2014-08-27
  • 2013-06-12
相关资源
最近更新 更多