如何避免“重复密钥”错误?

And*_*ykh 5 sql-server concurrency sql-server-2014

这个说法:

INSERT INTO deleteme
SELECT #t.id, 'test' FROM #t
LEFT JOIN  deleteme  ON deleteme.id = #t.id
WHERE deleteme.id IS NULL;
Run Code Online (Sandbox Code Playgroud)

...将在并发场景中因主键冲突而失败(即,当同时从多个线程插入 deleteme 中不存在的相同键时),默认事务隔离级别为READ COMMITTED

错误:违反 PRIMARY KEY 约束“PK_DeleteMe”。无法在对象“dbo.deleteme”中插入重复键。

防止这种情况的最佳方法是什么?

该表看起来像这样:

CREATE TABLE [dbo].[DeleteMe](
    [id] [uniqueidentifier] NOT NULL,
    [Value] [varchar](max) NULL,
CONSTRAINT [PK_DeleteMe] PRIMARY KEY ([id] ASC));
Run Code Online (Sandbox Code Playgroud)

更新

来自评论:

为什么你有多个会话,显然可以从某个地方提取相同的 id,使用相同的永久表而没有某种会话密钥来区分它们?即使没有重复错误,您如何知道哪些行属于哪个会话?

这是一个由填充此表中数据的外部服务调用的存储过程。该服务生成记录 ID,但不保证不会两次发送相同的数据。或者同时发送相同的数据。

数据库代码应该丢弃所有具有相同 id 的记录,如果一个记录已经存在。该服务绝不会在同一批次中发送两个具有相同 ID 的记录。

Aar*_*ron 10

如果您确实需要同时运行多个线程,您可以启用ignore_dup_key主键上的选项。

当插入会导致重复的键冲突时,这只会给出警告而不是错误。但它不会失败,而是丢弃如果插入会导致唯一性违规的行。

CREATE TABLE [dbo].[DeleteMe](
[id] [uniqueidentifier] NOT NULL,
[Value] [varchar](max) NULL,
CONSTRAINT [PK_DeleteMe] 
PRIMARY KEY ([id] ASC) 
WITH (IGNORE_DUP_KEY = ON));
Run Code Online (Sandbox Code Playgroud)

sqlfiddle 上的示例

Paul White 关于 IGNORE_DUP_KEY 选项的详细解释。谢谢保罗。