2011-03-02 62 views
0

我有一個名爲「計劃」的表,它充當多個進程/計算機頻繁訪問表的隊列機制。 proc的目標是拾取行數不超過行數的計數,並有資格被拾取(它們的LastCompletedProcessingId & LastStartedProcessingId必須匹配)並將它們標記爲已拾取(將LastStartedProcessingId更改爲NEWID()),以便下一個進程不會嘗試拾取已標記的行。爲什麼這個存儲過程偶爾不能正常工作?

我的問題是,在很少的時候,當多個客戶端在非常近的時間調用過程時,多個客戶端會得到相同的行。這怎麼可能?我如何避免它?桌子本身並不大。 @timeout不是一個問題,因爲這些事情不會花費超過300秒的時間來處理,而且我有一個日誌,在進程讀取多個記錄之前,它們沒有運行超過300秒。這是運行在SQL Azure

任何想法如何這可能嗎? 謝謝

CREATE PROCEDURE X 
    @count int, 
    @timeout int = 300 
AS 
BEGIN 
    SET NOCOUNT ON; 

    DECLARE @batchId uniqueidentifier 
    SELECT @batchId = NEWID() 

    BEGIN TRAN 

    -- Update rows 
    UPDATE Schedule 
    WITH (ROWLOCK) 
    SET 
     LastBatchId = @batchId, 
     LastStartedProcessingId = NEWID(), 
     LastStartedProcessingTime = GETDATE() 
    WHERE 
     AccountId IN (
      SELECT TOP (@count) AccountId 
      FROM Schedule 
      WHERE 
       (LastStartedProcessingId = LastCompletedProcessingId OR LastCompletedProcessingId IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) > @timeout) AND 
       (LastStartedProcessingTime IS NULL OR DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) > Frequency) 
      ORDER BY (DATEDIFF(SECOND, LastStartedProcessingTime, GETDATE()) - Frequency) DESC 
     ) 

    -- Return the changed rows 
    SELECT AccountId, LastStartedProcessingId, Frequency, LastProcessTime, LastConfigChangeTime 
    FROM Schedule 
    WHERE LastBatchId = @batchId 

    COMMIT TRAN 
END 
+0

更新聲明在選擇之前運行多長時間? – Sergey 2011-03-02 04:36:13

+0

我想我明白你要去哪裏。更新速度非常快,但時間也非常接近。但是,交易不應該允許同時更新到同一行嗎? – Igorek 2011-03-02 05:08:36

回答

1

除了使用ROWLOCK提示的,與設置爲序列的ISOLATION_LEVEL運行更新。

另外,如果您在更新中使用OUTPUT子句,則可以在更新完成後立即獲取受影響的行的列表。這意味着您可以儘快結束您的交易1 DML語句並保持您的ACIDity。

1

可能是您的問題?

當在快照隔離 級別操作的事務 指定,行鎖不採取除非 ROWLOCK與其它表合併 提示需要鎖的,如 UPDLOCK和HOLDLOCK。

Source

相關問題