2009-02-22 122 views
5

我有一個存儲過程,它選擇1記錄回來。存儲過程可以從不同的PC上的幾個不同的應用程序調用。這個想法是,存儲過程帶回需要處理的下一條記錄,並且如果兩個應用程序同時調用存儲過程,則不應該返回相同的記錄。我的查詢在下面,我試圖儘可能高效地編寫查詢(SQL 2008)。它能比這更有效地完成嗎?高效交易,記錄鎖定

CREATE PROCEDURE GetNextUnprocessedRecord 
AS 
BEGIN 
    SET NOCOUNT ON; 

    --ID of record we want to select back 
    DECLARE @iID BIGINT  

    -- Find the next processable record, and mark it as dispatched 
    -- Must be done in a transaction to ensure no other query can get 
    -- this record between the read and update 
    BEGIN TRAN 

     SELECT TOP 1 
      @iID = [ID] 
     FROM 
      --Don't read locked records, only lock the specific record 
      [MyRecords] WITH (READPAST, ROWLOCK) 
     WHERE 
      [Dispatched] is null 
     ORDER BY 
      [Received] 

     --Mark record as picked up for processing 
     UPDATE 
      [MyRecords] 
     SET 
      [Dispatched] = GETDATE() 
     WHERE 
      [ID] = @iID  

    COMMIT TRAN 

    --Select back the specific record 
    SELECT 
     [ID], 
     [Data] 
    FROM  
     [MyRecords] WITH (NOLOCK, READPAST) 
    WHERE 
     [ID] = @iID 

END 
+0

我不相信這個TSQL是事務安全... – 2009-02-22 08:07:45

+0

嘗試把一個WAITFOR DELAY「0:2:0」後的SELECT和UPDATE之前,運行SP,並從另一個連接實際執行同一SP ... – 2009-02-22 08:17:24

+0

,我錯了! HOLDLOCK與MyRecords表上的REPEATABLEREAD具有相同的效果。 – 2009-02-22 08:22:27

回答

3

使用READPAST鎖定提示是正確的,你的SQL看起來不錯。

我想補充使用XLOCK雖然這也是HOLDLOCK/SERIALIZABLE

... 
[MyRecords] WITH (READPAST, ROWLOCK, XLOCK) 
... 

這意味着你的ID,雖然你堅持下去,並更新其獨佔鎖定該行。

編輯:在調度和接收列添加一個索引,使之更快。如果[ID](我認爲它是PK)未被聚類,INCLUDE [ID]。和過濾指數也因爲它是SQL 2008

你也可以使用這個結構,它所有這一切一氣呵成,不XLOCK或HOLDLOCK

UPDATE 
    MyRecords 
SET 
    --record the row ID 
    @id = [ID], 
    --flag doing stuff 
    [Dispatched] = GETDATE() 
WHERE 
    [ID] = (SELECT TOP 1 [ID] FROM MyRecords WITH (ROWLOCK, READPAST) WHERE Dispatched IS NULL ORDER BY Received) 

UPDATE, assign, set in one

0

您可以爲每個選取器進程分配一個唯一的id,並將列pickerproc和pickstate添加到記錄中。然後

UPDATE MyRecords
SET pickerproc = myproc的,
pickstate = 'I' - 關於「I'n過程
其中id =(SELECT MAX(Id)的FROM MyRecords WHERE pickstate = 'A' ) - 「A'vailable

,讓你你在一個原子一步記錄,你可以在你的閒暇做你處理的其餘部分。然後,您可以將pickstate設置爲'C'完成','E'rror或任何其他解決方法。

我覺得米奇是指在您創建一個消息隊列表並插入IDS有另一種很好的技術。有幾個SO線程 - 搜索「消息隊列表」。

0

你可以保持MyRecords在「MEMORY」表更快的處理速度。