我有一些同步過程使用「LastUpdate」標誌來更新自上次同步嘗試以來更改的任何記錄。SQL合併,表值參數和GetDate()
稍後我更新了代碼以利用表值參數,而不是一次同步(添加/更新)一行。這是更快的10倍或更多。
但是,我現在遇到了一個競賽條件,有時會導致更新被錯過。我趕緊張羅了一些SQL腳本來測試我的情況/理論(任何大表ID將工作):
/*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
示例結果
ID RequestID PreDate MergeDate
1 169880 2016-05-13 13:57:54.643 2016-05-13 13:57:54.643
所以,你可以看到MergeDate(GETDATE( ))來自何時合併開始,而不是何時結束。
比賽條件可以是這樣的:
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
所有從合併的記錄將被跳過。事實上,這種競爭狀態很少發生,因爲我們正在說毫秒而不是幾分鐘,但它確實發生了。
問題是...沒有運行第二個腳本來重新更新LastUpdate與合併後的日期,有沒有什麼辦法讓合併語句使用它完成工作的日期而不是當它開始了嗎?