2009-02-22 76 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”表更快的处理速度。