我们有一个工单表。服务器代理作业从游标中的该表中获取 100 个条目并执行一些工作。为了并行化,有 10 个服务器代理作业,它们调用以下过程(每个都有自己的@process_id
):
CREATE PROCEDURE sp_do_workorder @process_id INT
AS
BEGIN TRY
DECLARE @wo_id NCHAR(40),
@wo_action NVARCHAR(100),
@created_at DATETIME,
@source_proc_name NVARCHAR(100),
UPDATE procedure_ctrl SET [status]='running' WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='idle'
WHILE 1=1
BEGIN
IF NOT EXISTS (SELECT * FROM procedure_ctrl WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='running') BREAK
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION
UPDATE workorder SET hash=CAST(@process_id AS NVARCHAR(100))
FROM workorder x
INNER JOIN (
SELECT TOP 100 id FROM workorder WHERE hash='' AND workorder_step=0 ORDER BY created_at ASC
) y ON x.id=y.id
COMMIT TRANSACTION
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
DECLARE wo_cur CURSOR FAST_FORWARD FOR SELECT id,action,created_at,optin_source FROM workorder WHERE hash=CAST(@process_id AS NVARCHAR(100)) AND workorder_step=0 ORDER BY created_at ASC
OPEN wo_cur
FETCH NEXT FROM wo_cur INTO @wo_id,@wo_action,@created_at,@source_proc_name
WHILE @@FETCH_STATUS=0
BEGIN
EXEC sp_basisprozess @wo_id,@wo_action,@created_at,@source_proc_name,@process_id
FETCH NEXT FROM wo_cur INTO @wo_id,@wo_action,@created_at,@source_proc_name
END
CLOSE wo_cur
DEALLOCATE wo_cur
WAITFOR DELAY '00:00:01'
END
UPDATE procedure_ctrl SET [status]='idle' WHERE [procedure]='sp_do_workorder_'+CAST(@process_id AS NVARCHAR(100)) AND [status]='running'
END TRY
BEGIN CATCH
EXEC dbo.sp_listerror
DECLARE @error NVARCHAR(4000)
SET @error='[sp_do_workorder]_'+CAST(@process_id AS NVARCHAR(100))+': critical problem'
RAISERROR(@error, 12, 1)
END CATCH
对于这 10 个代理工作中的大多数,我们经常遇到僵局。有没有人暗示为什么会这样?为了防止副作用,我们使用序列化事务隔离级别,因此只有一个代理作业可以获取一个工作订单条目。如果不设置事务隔离,即使死锁消失了,但通常会发生两个(或更多)代理作业获取相同的工作订单条目。