Kni*_*ins 5 sql sql-server sql-server-2016
假设MyTable的表结构(MyTableId NVARCHAR(MAX)PRIMARY KEY,NumberOfInserts INTEGER).
我经常需要更新,即递增现有记录的计数器,或者如果不存在,则为NumberOfInserts插入值为0的新记录.
实质上:
IF (MyTableId exists)
run UPDATE command
ELSE
run INSERT command
Run Code Online (Sandbox Code Playgroud)
我担心的是由于竞争条件等原因而丢失数据.
什么是最安全的写这种方式?
如果可能的话,我需要100%准确,并且愿意在必要时牺牲速度.
MERGE语句既可以执行UPDATE,也可以执行INSERT(DELETE如果需要).
即使它是单个原子语句,使用HOLDLOCK查询提示来防止竞争条件也很重要.Dan Guzman 有一篇博客文章"UPSERT"与MERGE的比赛条件,他详细解释了它是如何工作的,并提供了一个测试脚本来验证它.
查询本身很简单:
DECLARE @NewKey NVARCHAR(MAX) = ...;
MERGE INTO dbo.MyTable WITH (HOLDLOCK) AS Dst
USING
(
SELECT @NewKey AS NewKey
) AS Src
ON Src.NewKey = Dst.[Key]
WHEN MATCHED THEN
UPDATE
SET NumberOfInserts = NumberOfInserts + 1
WHEN NOT MATCHED THEN
INSERT
(
[Key]
,NumberOfInserts
)
VALUES
(
@NewKey
,0
);
Run Code Online (Sandbox Code Playgroud)
当然,您也可以使用显式两步方法,单独检查行是否存在以及单独UPDATE和INSERT语句.只需确保使用适当的表锁定提示将它们全部包装在事务中.
有关详细信息,请参阅Dan Guzman的条件INSERT/UPDATE竞争条件.