Veuillez arrêter d'utiliser l'anti-pattern UPSERT (SQL Server)

Pour les futurs étudiants du cours "MS SQL Server Developer" a préparé une traduction de l'article.



Nous vous invitons également à regarder le webinaire ouvert sur "Graph Databases in SQL Server" . Dans cette leçon, les participants, avec un expert, examineront ce que sont les bases de données de graphiques et quelles sont les options pour travailler avec des graphiques et des hiérarchies dans SQL Server.






Je pense que tout le monde connaît déjà mon opinion sur MERGE et pourquoi je m'en éloigne. Mais voici un autre anti-pattern que je rencontre constamment lorsqu'il est nécessaire d'exécuter UPSERT (UPdate inSERT - update a row if it exists, and insert if it does not exist):





IF EXISTS (SELECT 1 FROM dbo.t WHERE [key] = @key)
BEGIN
  UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
ELSE
BEGIN
  INSERT dbo.t([key], val) VALUES(@key, @val); 
END
      
      



Cela a l'air assez logique et correspond à la façon dont nous y pensons:





  • Y a-t-il une chaîne pour la clé donnée?





    • OUI : Nous mettons à jour cette ligne.





    • : .





, , , — . , (, , ). -, , :





Notez que deux opérations d'indexation seront effectuées sur chaque branche.
, .

, , , ( ):





  • UPDATE , ( "", "" " "). , . (Paul White) , (Martin Smith) .





  • , INSERT :





    • (deadlock) - ;





    • (key violation), ;





    • , .





— , . , XACT_ABORT , — , . , IF EXISTS ( ), . , , .





« ...»

(Dan Guzman) Conditional INSERT/UPDATE Race Condition, "UPSERT" Race Condition With MERGE.





(Michael Swart) Mythbusting: Concurrent Update/Insert Solutions, , , . MERGE Be Careful with the Merge Statement. .





, ( , ):





BEGIN TRANSACTION;
 
UPDATE dbo.t WITH (UPDLOCK, SERIALIZABLE) SET val = @val WHERE [key] = @key;
 
IF @@ROWCOUNT = 0
BEGIN
  INSERT dbo.t([key], val) VALUES(@key, @val);
END
 
COMMIT TRANSACTION;
      
      



? UPDLOCK ?





  • UPDLOCK ( , ). 





  • SERIALIZABLE ( , ). 





, 1000% . ( ) . , , , . , :





Dans ce cas, il existe une branche qui n'effectue qu'une seule recherche d'index.
, .

:





  • , , . 





  • , «» . ( ), UPDATE. 





, , - , «» .





, . , . , , .





, UPDATE ?

, UPDATE . , , INSERT, INSERT , UPDATE, UPSERT:





BEGIN TRANSACTION;
 
INSERT dbo.t([key], val) 
  SELECT @key, @val
  WHERE NOT EXISTS
  (
    SELECT 1 FROM dbo.t WITH (UPDLOCK, SERIALIZABLE)
      WHERE [key] = @key
  );
 
IF @@ROWCOUNT = 0
BEGIN
  UPDATE dbo.t SET val = @val WHERE [key] = @key;
END
 
COMMIT TRANSACTION;
      
      



« », INSERT :





BEGIN TRANSACTION;
 
BEGIN TRY
  INSERT dbo.t([key], val) VALUES(@key, @val);
END TRY
BEGIN CATCH
  UPDATE dbo.t SET val = @val WHERE [key] = @key;
END CATCH
 
COMMIT TRANSACTION;
      
      



. / . .





?

INSERT / UPDATE, (Justin Pealing) , , , ?





- (TVP, Table-Valued Parameters), UPDATE JOIN, INSERT, NOT EXISTS. , :





CREATE PROCEDURE dbo.UpsertTheThings
    @tvp dbo.TableType READONLY
AS
BEGIN
  SET NOCOUNT ON;
 
  BEGIN TRANSACTION;
 
  UPDATE t WITH (UPDLOCK, SERIALIZABLE) 
    SET val = tvp.val
  FROM dbo.t AS t
  INNER JOIN @tvp AS tvp
    ON t.[key] = tvp.[key];
 
  INSERT dbo.t([key], val)
    SELECT [key], val FROM @tvp AS tvp
    WHERE NOT EXISTS (SELECT 1 FROM dbo.t WHERE [key] = tvp.[key]);
 
  COMMIT TRANSACTION;
END
      
      



- , TVP (XML, - ..), JOIN . INSERT — UPDATE .





UPSERT- , , , , . , IF EXIST. (Paul White, sql.kiwi | @SQK_Kiwi) — .





MERGE (, - MERGE-), .






"MS SQL Server Developer".





« SQL Server».








All Articles