2016-07-06 7 views
3

MyTable(MyTableId NVARCHAR(MAX)PRIMARY KEY、NumberOfInserts INTEGER)のテーブル構造を仮定します。SQL ServerのINSERTまたはUPDATEに対する安全なソリューション2016

NumberOfInsertsの値が0でない場合は、既存のレコードのカウンタを増分するか、新しいレコードを挿入する必要があることがよくあります。基本的に

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

私の関心は、競合状態に起因するデータを失っている、など

これを書くために最も安全な方法は何ですか?

可能であれば100%の精度が必要で、必要な場合は速度を犠牲にしてください。

+0

MERGEコマンドを使用すると、一度にすべての更新、挿入、削除を組み合わせることができます。いくつかの観測結果は、SQL Serverの予約語である「キー」という列を呼び出さないでください。また、それを主キーとして使用していますか?もしそうなら、NVARCHAR(MAX)は本当に悪い考えです。 –

答えて

4

MERGEステートメントは、UPDATEINSERT(および必要に応じてDELETE)の両方を実行できます。

1つのアトミックステートメントでも、競合状態を防ぐにはクエリヒントHOLDLOCKを使用することが重要です。 Dan Guzmanのブログ記事“UPSERT” Race Condition With MERGEがあります。ここで彼はどのように動作し、それを検証するためのテストスクリプトを提供しているかを詳細に説明しています。

クエリ自体は単純明快です:行が存在し、独立したUPDATEINSERT if文もちろん

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 
); 

、あなたはまた、別のチェックを明示的に2段階のアプローチを使用することができます。適切なテーブルロックヒントを使用して、それらをすべてトランザクション内にラップするようにしてください。

詳しくは、Dan GuzmanのConditional INSERT/UPDATE Race Conditionを参照してください。

+0

MERGEを使用する場合は注意してください。それに大きな問題があります: https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –

関連する問題