2016-07-06 1 views
3

Supposons une structure de table de MyTable (MyTableId NVARCHAR (MAX) PRIMARY KEY, NumberOfInserts INTEGER).Solutions sécurisées pour INSERT AND UPDATE sur SQL Server 2016

Je dois souvent soit mettre à jour, c'est-à-dire incrémenter un compteur d'un enregistrement existant, soit insérer un nouvel enregistrement s'il n'existe pas avec la valeur 0 pour NumberOfInserts.

essentiellement:

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

Ma préoccupation est en train de perdre des données en raison de la race des conditions, etc.

Quelle est la manière la plus sûre pour écrire cela?

J'ai besoin d'être précis à 100% si possible, et prêt à sacrifier la vitesse si nécessaire.

+0

Vous pouvez utiliser la commande MERGE pour combiner, mettre à jour, insérer et supprimer tous en même temps. Couple d'observations, s'il vous plaît ne pas appeler cette colonne «clé» c'est un mot réservé dans SQL Server. Aussi, utilisez-vous cela comme clé primaire? Si c'est le cas, NVARCHAR (MAX) est une très mauvaise idée. –

Répondre

4

déclaration MERGE peut effectuer à la fois UPDATE et INSERT (et DELETE si nécessaire).

Même s'il s'agit d'une instruction atomique unique, il est important d'utiliser l'indicateur de requête HOLDLOCK pour éviter les conditions de concurrence. Il ya un article de blog “UPSERT” Race Condition With MERGE par Dan Guzman où il explique dans les moindres détails comment cela fonctionne et fournit un script de test pour le vérifier.

La requête elle-même est directe:

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

Bien sûr, vous pouvez également utiliser l'approche explicite en deux étapes avec un chèque séparé si une ligne existe et UPDATE et INSERT séparés déclarations. Assurez-vous juste de les emballer tous dans une transaction avec des conseils de verrouillage de table appropriés.

Voir Conditional INSERT/UPDATE Race Condition par Dan Guzman pour plus de détails.

+0

Soyez prudent en utilisant MERGE ... il y a une tonne de problèmes avec: https://www.mssqltips.com/sqlservertip/3074/use-caution-with-sql-servers-merge-statement/ –