Ich habe einige Synchronisationsprozesse, die ein Flag "LastUpdate" verwenden, um alle Datensätze zu aktualisieren, die seit dem letzten Synchronisierungsversuch geändert wurden.SQL-Merge, Tabellenwertparameter und GetDate()
Vor einiger Zeit habe ich den Code aktualisiert, um Tabellenwerte zu verwenden, anstatt eine Zeile auf einmal zu synchronisieren (hinzufügen/aktualisieren). Dies ist 10 mal oder mehr schneller.
Allerdings bin ich jetzt auf eine Race Condition gestoßen, die manchmal zu Updates führt. Ich schnell einig SQL-Skript rauschte bis zu meiner Situation/Theorie zu testen (jede große Tabelle mit IDs arbeiten):
/*CREATE TYPE IntTable AS TABLE(
[RequestID] [int] NOT NULL
)
GO
CREATE TABLE MergeTest(
[ID] [int] IDENTITY(1,1) NOT NULL,
[RequestID] [int] NOT NULL,
[PreDate] [datetime] NOT NULL,
[MergeDate] [datetime] NOT NULL
GO
*/
DECLARE @requestIDs As IntTable
INSERT INTO @requestIDs
SELECT RequestID FROM Request
DECLARE @preDate As DateTime = Getdate()
MERGE INTO MergeTest USING @requestIDs SRC
ON MergeTest.RequestID = SRC.RequestID
WHEN MATCHED THEN
UPDATE SET PreDate = @preDate, MergeDate = GetDate()
WHEN NOT MATCHED THEN
INSERT (RequestID, PreDate, MergeDate)
VALUES (SRC.RequestID, @preDate, GetDate());
SELECT TOP 100 * FROM MergeTest
Beispiel Ergebnis
ID RequestID PreDate MergeDate
1 169880 2016-05-13 13:57:54.643 2016-05-13 13:57:54.643
So können Sie sehen, dass die MergeDate (GetDate ()) ist ab wann die Zusammenführung beginnt, nicht wenn sie endet.
Die Race-Bedingung kann das sein:
Check what has been updated since 14:59
Start a merge at 15:00
Check what has been updated since 15:00
Merge completes, but with a LastUpdate of 15:00
Check what has been updated since 15:01
Alle Datensätze aus der Zusammenführung würde übersprungen. In der Realität tritt diese Race Condition sehr selten auf, weil wir Millisekunden statt Minuten sprechen, aber es passiert.
Die Frage ist ... ohne ein zweites Skript zu laufen, das LastUpdate mit einem Post-Merge-Datum neu zu aktualisieren, gibt es eine Möglichkeit, die Merge-Anweisung das Datum zu verwenden, dass es den Auftrag beendet hat, anstatt wann begann es?