Bitte beenden Sie die Verwendung von UPSERT Anti-Pattern (SQL Server).

Für zukünftige Studenten des Kurses "MS SQL Server Developer" wurde eine Übersetzung des Artikels vorbereitet.



Wir laden Sie außerdem ein, das offene Webinar zum Thema "Grafikdatenbanken in SQL Server" anzusehen . In dieser Lektion werden die Teilnehmer zusammen mit einem Experten untersuchen, was Diagrammdatenbanken sind und welche Optionen für die Arbeit mit Diagrammen und Hierarchien in SQL Server verfügbar sind.






Ich denke, jeder kennt bereits meine Meinung zu MERGE und warum ich mich davon fern halte . Aber hier ist ein weiteres Anti-Pattern, auf das ich ständig stoße, wenn UPSERT ausgeführt werden muss (UPdate inSERT - Aktualisieren Sie eine Zeile, falls vorhanden, und fügen Sie sie ein, wenn sie nicht vorhanden ist):





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
      
      



Es sieht ziemlich logisch aus und passt zu unserer Denkweise:





  • Gibt es eine Zeichenfolge für den angegebenen Schlüssel?





    • JA : Wir aktualisieren diese Zeile.





    • : .





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





Beachten Sie, dass für jeden Zweig zwei Indexoperationen ausgeführt werden.
, .

, , , ( ):





  • 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% . ( ) . , , , . , :





In diesem Fall gibt es einen Zweig, der nur eine Indexsuche durchführt.
, .

:





  • , , . 





  • , «» . ( ), 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