SQL Server 2005中的原子UPSERT [英] Atomic UPSERT in SQL Server 2005

查看:250
本文介绍了SQL Server 2005中的原子UPSERT的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在SQL Server 2005中执行原子"UPSERT"(存在的话更新,否则插入)的正确模式是什么?

What is the correct pattern for doing an atomic "UPSERT" (UPDATE where exists, INSERT otherwise) in SQL Server 2005?

我在SO上看到很多代码(例如,参见检查是否存在一行,否则插入)并使用以下两部分模式:

I see a lot of code on SO (e.g. see Check if a row exists, otherwise insert) with the following two-part pattern:

UPDATE ...
FROM ...
WHERE <condition>
-- race condition risk here
IF @@ROWCOUNT = 0
  INSERT ...

IF (SELECT COUNT(*) FROM ... WHERE <condition>) = 0
  -- race condition risk here
  INSERT ...
ELSE
  UPDATE ...

其中< condition>将是自然键的评估.上述方法似乎都不能很好地处理并发.如果我不能让两行具有相同的自然键,则上述所有情况似乎都存在在竞争条件场景中插入具有相同自然键的行的风险.

where < condition > will be an evaluation of natural keys. None of the above approaches seem to deal well with concurrency. If I cannot have two rows with the same natural key, it seems like all of the above risk inserting rows with the same natural keys in race condition scenarios.

我一直在使用以下方法,但很惊讶没有在人们的回应中看到它,所以我很想知道这是怎么回事:

I have been using the following approach but I'm surprised not to see it anywhere in people's responses so I'm wondering what is wrong with it:

INSERT INTO <table>
SELECT <natural keys>, <other stuff...>
FROM <table>
WHERE NOT EXISTS
   -- race condition risk here?
   ( SELECT 1 FROM <table> WHERE <natural keys> )

UPDATE ...
WHERE <natural keys>

请注意,此处提到的竞争条件不同于先前代码中的竞争条件.在较早的代码中,问题是幻像读取(行在其他会话之间插入到UPDATE/IF之间或SELECT/INSERT之间).在上面的代码中,竞争条件与DELETE有关.在(WHERE NOT EXISTS)执行之后但在INSERT执行之前,是否可以将另一个行删除匹配的行?目前尚不清楚WHERE NOT EXISTS在哪里与UPDATE结合使用来锁定任何内容.

Note that the race condition mentioned here is a different one from the ones in the earlier code. In the earlier code, the issue was phantom reads (rows being inserted between the UPDATE/IF or between the SELECT/INSERT by another session). In the above code, the race condition has to do with DELETEs. Is it possible for a matching row to be deleted by another session AFTER the (WHERE NOT EXISTS) executes but before the INSERT executes? It's not clear where the WHERE NOT EXISTS puts a lock on anything in conjunction with the UPDATE.

这是原子的吗?我找不到在SQL Server文档中将其记录在何处.

Is this atomic? I can't locate where this would be documented in SQL Server documentation.

我意识到这可以通过事务来完成,但是我想我需要将事务级别设置为SERIALIZABLE以避免幻像读取问题?这样的常见问题肯定是过分杀伤力的吗?

I realise this could be done with transactions, but I think I would need to set the transaction level to SERIALIZABLE to avoid the phantom read problem? Surely that is overkill for such a common problem?

推荐答案

INSERT INTO <table>
SELECT <natural keys>, <other stuff...>
FROM <table>
WHERE NOT EXISTS
   -- race condition risk here?
   ( SELECT 1 FROM <table> WHERE <natural keys> )

UPDATE ...
WHERE <natural keys>

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆