2016-07-06 73 views
3

假設MyTable的表結構(MyTableId NVARCHAR(MAX)PRIMARY KEY,NumberOfInserts INTEGER)。SQL Server 2016上INSERT或UPDATE的安全解決方案

我經常需要更新(即遞增現有記錄的計數器),或者在NumberOfInserts中不存在值爲0的情況下插入新記錄。

本質:

IF (MyTableId exists) 
    run UPDATE command 
ELSE 
    run INSERT command 

我擔心的是,由於失去競爭條件數據等

什麼是寫這個最安全的方式

如果可能,我需要它100%準確,並且願意在必要時犧牲速度。

+0

您可以使用MERGE命令查看,它一次性組合更新,插入和刪除。幾個觀察,請不要稱該列'鍵'它是SQL Server中的保留字。另外,你使用它作爲主鍵嗎?如果是這樣,NVARCHAR(MAX)是一個非常糟糕的主意。 –

回答

4

MERGE語句可以執行UPDATEINSERT(和DELETE如果需要)。

儘管它是單個原子語句,但使用HOLDLOCK查詢提示來防止競爭條件很重要。在Dan Guzman的博客文章「UPSERT」 Race Condition With 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 
); 

當然,你也可以用明確的兩步法有獨立的檢查,如果一個行存在和獨立UPDATEINSERT語句。只要確保將它們全部包含在具有適當的表鎖定提示的事務中。細節請參閱Dan Guzman的Conditional INSERT/UPDATE Race Condition

+0

小心使用MERGE ...有很多問題: https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –