У нас есть рабочий стол. Задания агента сервера собирают 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 рабочих мест агентов. Кто-нибудь намекнул, почему это так? Чтобы предотвратить побочные эффекты, мы используем сериализацию уровня изоляции транзакций, поэтому только одно задание агента может захватить одну запись рабочего заказа. Без установки изоляции транзакции leven тупик исчезает, но часто случается, что два (или более) задания агента захватывают одну и ту же запись рабочего задания.