Блокировка процесса?

Добрый день! есть следующая проблема. Для автоматизации учета дебиторской задолженности был создан раздел. Записи в данный раздел попадают при добавлении счетов. Был создан триггер который срабатывает при UPDATE, Insert , Delete таблицы tbl_Invoice.Но при подгрузке большого количества счетов из Excel файла SQL server выдает ошибку дословно следующую "Транзакция (идентификатор процесса 142) вызвала взаимоблокировку ресурсов буфер связи с другим процессом и стала жертвой взаимоблокировки. Запустите транзакцию повторно". Триггер запускает хранимую процедуру. Возможно стоит запускать ее в обработчике датасета счета? Подскажите пожалуста?

Код триггера.

ALTER TRIGGER [dbo].[tr_InvoiceAsDebtorUpdate]
   ON  [dbo].[tbl_Invoice]
   after INSERT,DELETE,UPDATE
AS
BEGIN
        SET NOCOUNT ON;
        declare @ContractID uniqueidentifier;
        declare @access int
        SET @access = 0
       
               
       
        IF EXISTS(SELECT ContractID FROM inserted)
                        begin
                                SET @ContractID =(SELECT top 1 ContractID FROM [Inserted])
                                IF (UPDATE(Amount) OR UPDATE(PaymentAmount))
                                        begin
                                                SET @access  = 1;
                                        end
                               
                        end
                else
                        begin
                                SET @ContractID =(SELECT top 1 ContractID FROM [Deleted])
                                SET @access  = 1;
                        end    
       
        IF (@ContractID IS NULL)
                begin
                        RETURN
                end
               
        IF (@access = 1)
                begin  
       
                        exec [dbo].[sp_CreateDebtor] @ContractID
                end
END

Нравится

10 комментариев

Здравствуйте Иван,
Не уверен что переписывание логики на событие Post Dataset'а поможет исправить ситуацию, в принципе, наверное стоит понять что собственно блокирует транзакцию, это можно сделать как описано http://www.mssqltips.com/sqlservertip/1036/finding-and-troubleshooting-…

Если вы конечно захотите реализовать вызов хранимой процедуры через события датасета, то это можно сделать следующим образом http://www.community.terrasoft.ru/forum/topic/7030#comment-30105

Как вариант импорта могу посоветовать делать Insert на прямую в таблицу через SQL Server посмотреть как это сделать можно по следующей ссылке http://www.community.terrasoft.ru/forum/topic/6954#comment-29730

Я предполагаю что блокирует транзакцию обновление таблицы дебиторов. А как это обойти?

Можете пожалуйста привести код хранимой процедуры sp_CreateDebtor

ALTER PROCEDURE [dbo].[sp_CreateDebtor]
(@ContractID uniqueidentifier)
AS
BEGIN
	SET NOCOUNT ON;
 
	declare @DelayDebt decimal(15,4)
	declare @AllDebt decimal(15,4)
	declare @CurrentDebt decimal(15,4)
	set @DelayDebt = (select [dbo].[f_getDebtorDolg](@ContractID,3))
	set @AllDebt = (select [dbo].[f_getDebtorDolg](@ContractID,2))
	set @CurrentDebt =  (select [dbo].[f_getDebtorDolg](@ContractID,1))	
 
	if (not EXISTS(select ContractID from tbl_Debtor db where db.ContractID = @ContractID))
		or (EXISTS(select ContractID 
			from tbl_Debtor db1 
			left join
			tbl_DebtorState as ds on ds.ID = db1.StateID
			where db1.ContractID = @ContractID
			and ds.Code = 'Close' 
			and db1.DebtDate = (select MAX(ISNULL(DebtDate,GETDATE())) from tbl_Debtor db3 
									where @ContractID = db3.ContractID)))
	begin
 
		if not EXISTS(select 
		SUM(ISNULL(i.PaymentAmount,0)) - SUM(ISNULL(i.Amount,0))
		from tbl_Invoice i
		left join 
		tbl_Contract as c on c.ID = i.ContractID
		where not ContractID is null
		and c.ContractTypeID = 'ED7FD7B2-46A7-4583-8FB4-37356272EB8A'
		and contractID	= @ContractID
		group by ContractID
		HAVING SUM(ISNULL(i.PaymentAmount,0)) - SUM(ISNULL(i.Amount,0)) < 0 )
		begin
			return
		end
 
		insert into tbl_Debtor
		(ID,CreatedOn,ContractID,DebtDate,AccountID,DebtorNumber,StateID,ActionID,
		DelayDebt, AllDebt, CurrentDebt,IsOff)
		Values(
			newID(),
			GETDATE(), 
			@ContractID,
			GETDATE()
			,(select CustomerID from tbl_Contract where ID = @ContractID)
			,Cast(Month(GetDate())as varchar(5))+substring(Cast(YEAR(GetDate())as varchar(5)),3,5)+
			 (select ContractNumber from tbl_Contract where ID = @ContractID)
			,(select ID from tbl_DebtorState where Code = 'New')
			,(select ID from tbl_DebtorAction where IsStart = 1)
			,@DelayDebt
			,@AllDebt
			,@CurrentDebt
			,0)
			-----exec [dbo].[sp_SetAccessDebtor] @ContractID
	end
	else	
		begin
			update tbl_Debtor
				set CurrentDebt = @CurrentDebt, 
					AllDebt = @AllDebt,
					DelayDebt = @DelayDebt
 
			where tbl_Debtor.ContractID = @ContractID
				  and 
			tbl_Debtor.DebtDate = (select MAX(ISNULL(db3.DebtDate,GETDATE())) from tbl_Debtor db3 
									where @ContractID = db3.ContractID)	
 
		end
 
 
END

Попытался воспроизвести проблемму, создав sp_CreateDebtor , и использовать триггер в 1м посте, создал импорт с Excel, проблемму вопспроизвести не удалось импорт делался на 1000 записей. Сколько записей вы импортируете, возможно проблему обойти импортируя меньшее колиечство записей ?

Create PROCEDURE [dbo].[sp_CreateDebtor]
(@ContractID uniqueidentifier)
AS
BEGIN
        SET NOCOUNT ON;
 
        declare @DelayDebt decimal(15,4)
        declare @AllDebt decimal(15,4)
        declare @CurrentDebt decimal(15,4)
 
        begin
 
                IF NOT EXISTS(SELECT
                SUM(ISNULL(i.PaymentAmount,0)) - SUM(ISNULL(i.Amount,0))
                FROM tbl_Invoice i
                LEFT JOIN
                tbl_Contract AS c ON c.ID = i.ContractID
                WHERE NOT ContractID IS NULL
                AND c.ContractTypeID = 'ED7FD7B2-46A7-4583-8FB4-37356272EB8A'
                AND contractID  = @ContractID
                GROUP BY ContractID
                HAVING SUM(ISNULL(i.PaymentAmount,0)) - SUM(ISNULL(i.Amount,0)) < 0 )
                begin
                        RETURN
                end
 
 
		end	              
END

Импортируется порядка 400 строк но помимо данных еще идет подгрузка файлов. И в вашем посте в процедуре отсутствует Update и Inserte таблицы. Мне кажется что проблема кроется в них.

Возможно ли передача backup’а базы данных нам, для того что бы могли помочь вам в решении поставленной перед вами задачу?

К сожалению возможности передать дамп базы не представляется возможным.

Иван,
Предлагаю вам последовать рекомендациям в статье
http://www.rsdn.ru/article/db/deadlocks.xml#ECMAE

Возможно установление некой задержки

WAITFOR DELAY '00:00:10'

и установка различных уровней изоляции помогут решить проблему

Спасибо) Я в данный момент склоняюсь к варианту отказа от триггеров и создания job который раз в час например пересчитывает задолженность и обновляет записи.

Показать все комментарии