我有一個包含數千個條目的數據庫表。我有多個工作線程一次接一行,做一些工作(每次大約需要一秒)。在拾取行時,每個線程都會更新數據庫行上的一個標誌(如時間戳),以便其他線程不會將其選中。但問題是,我最終在多個線程正在拾取同一行的情況下。從數據庫表上的多個線程查詢
我的一般問題是,我應該在這裏遵循什麼樣的通用設計方法來確保每個線程都獨立地選擇唯一的行並完成他們的任務。
注意:多個線程並行運行以加快數據庫行的處理速度。所以我想要儘可能小的關鍵部分或排他鎖。
只是爲了給出一些上下文,下面是存儲過程,它在更新行上的標誌後從表中拾取行。請注意,存儲過程不可編譯,因爲我已從中刪除了不必要的部分。但通常這就是它的結構。
多線程並行執行存儲過程時會發生問題。在一個線程中更新語句所做的更改(請注意更新在鎖定之後完成)對其他線程不可見,除非事務已提交。由於在UPDATE和TRANSACTION COMMIT之間有一條SELECT語句(大約需要50ms),在20%的情況下,線程中的UPDATE語句會選取一條已經被處理的行。
我希望我在這裏清楚。
USE ['mydatabase']
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
ALTER PROCEDURE [dbo].[GetRequest]
AS
BEGIN
-- some variable declaration here
BEGIN TRANSACTION
-- check if there are blocking rows in the request table
-- FM: Remove records that don't qualify for operation.
-- delete operation on the table to remove rows we don't want to process
delete FROM request where somecondition = 1
-- Identify the requests to process
DECLARE @TmpTableVar table(TmpRequestId int NULL);
UPDATE TOP(1) request
WITH (ROWLOCK)
SET Lock = DateAdd(mi, 5, GETDATE())
OUTPUT INSERTED.ID INTO @TmpTableVar
FROM request tur
WHERE (Lock IS NULL OR GETDATE() > Lock) -- not locked or lock expired
AND GETDATE() > NextRetry -- next in the queue
IF(@@RowCount = 0)
BEGIN
ROLLBACK TRANSACTION
RETURN
END
select @RequestID = TmpRequestId from @TmpTableVar
-- Get details about the request that has been just updated
SELECT somerows
FROM request
WHERE somecondition = 1
COMMIT TRANSACTION
END
您可以發佈表'request'的列? –
@IgorPaiva我更新了問題 – Dibzmania