Добрый день, уважаемое сообщество.
Проявилась такая проблема в этом году. Возможно связано с большим количеством записей в базе данных. Но не факт.
Описание:
Terrasoft XRM 3.3.2.304.
Существует несколько расходных накладных.
Скрипт вызывает стандартную функцию ConductSelectedOfferingMovements:
В Data.OfferingMovementIDs передается массив ID складских документов.

                Data.IsRecalcPrimeCost = false;
                Data.IsConduct = true;
                Data.OfferingMovementStatus = omsCompleted;
                Data.IsRecalcOfferingPrices = false;
                Data.IsUpdateShipmentState = false;
                Data.IsUpdatePurchaseState = false;
                Data.IsReserveOfferingsFromOrders=false;
                Data.IsAddSupplierInOffering = false;
                var Result = ConductSelectedOfferingMovements(Data);

Все выполняется правильно, но пока идет выполнение этой функции на одном из рабочих мест, у других пользователей, работающих с разделами Склад (деталь Продукты)
или Продукты(деталь Складские документы), появляется ошибка "Ошибка открытия источника данных ds_MovementInOffering. Превышено время ожидания запроса на блокировку".
Изменений в функцию и хранимые процедуры не вносили.
Ошибка повторяется на 100 процентов.
Во время выполнения хранимой процедуры ошибка открытия может быть и для ds_Account и других
источников данных.
Сталкивался ли кто-нибудь с такой проблемой и в чем ее причина?

Нравится

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

Здравствуйте, Виктор.
Нужно тюнить базу, может помочь индексация используемых в ХП колонок.
Скорее всего, транзакция запущенная по ХП блокирует используемые таблицы, которые параллельно пытаются использовать пользователи с других рабочих мест.

Максим, добрый день.
Мы тут примерно в эту сторону и копаем. Похоже ХП блокирует tbl_MovementInOM. Мы убрали подзапросы в разделах и деталях, которые ее использовали. Но в том же ds_Offering поле Remain это подзапрос к этой таблице. Отсюда и ошибки.
По индексации: я правильно понимаю, что нужно добиваться того, чтобы ХП быстрее обрабатывала блокируемую таблицу?

Да, это один из вариантов. Насколько мне известно есть еще и возможности предотвращения дедлоков путем их приоритезации. Но каких либо конкретных рекомендаций дать не смогу, простите.

Возможно, эти статьи будут полезными:
http://technet.microsoft.com/ru-ru/library/ms189081.aspx
http://samag.ru/archive/article/797

Во время выполнения ХП закрытия документа SQL сервер грузит процессор на 100%. Это нормально?

Виктор, видимо обработка больших данных несет большую нагрузку. Может быть мощности не хватает.
Как долго выполняется хранимка?

Проверял на тестовой базе.
Всего в этой базе 87 складских документов, т.е. нет больших данных на мой взгляд. Выполняется закрытие практически мгновенно. Но делаем закрытие в цикле нескольких расходных, и на это время загрузка процессора 100%.
И еще один момент. К моей радости он пока проявляется только на тестовом сервере. Любая конфигурация от самых старых до текущей копии рабочей базы. Закрытие документа с недостаточным количеством продукта в остатках(т.е. остаток 100, а списываю 101) приводит не к сообщению о недостаточном количестве, а полностью вешает клиента. Процессор на сервере загружен на 100%, пока аварийно не завершу клиента. Часами я конечно не ждал результата. Думаю, что-то с SQL сервером (2008). Будем разбираться.
С другой стороны анализируем ХП, чтобы понять в каком месте мы зависаем.

Новые данные. Виснет если по продукту указан метод списания Средневзвешенный и есть несколько приходов по ним.
зацикливается в tsp_OfferingDistribute
не может закончится цикл:

while (@ARemainQuantity >= @AUnitDivision)
begin
	OPEN Consignment_Cursor
	FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentID, @ConsignmentQuantity
	WHILE @@FETCH_STATUS = 0
	BEGIN
		if (@ARemainQuantity < @AUnitDivision) 
			break
		update #ListQuantity 
		set Quantity=Quantity + @AUnitDivision 
		where ConsignmentID=@ConsignmentID
			and Quantity < @ConsignmentQuantity
		if (@@ROWCOUNT > 0) 
			set @ARemainQuantity = @ARemainQuantity - @AUnitDivision
		FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentID, @ConsignmentQuantity
	END
	CLOSE Consignment_Cursor
end

Похоже выяснили причину зависания.
Пример:
Два прихода по продукту с количествами 1000 и 100.
Проводим.
Расходная с количеством 3500.
Зависание.
Дело в том что 3500 делится на части пропорционально остаткам по партиям.
Т.е получаем 3181,818 и 318,1818. И если правильно округлить, то 3182 и 318, что в сумме даст 3500.

Причина в ХП tsp_RoughOfferingDistribute

DECLARE Consignment_Cursor CURSOR FOR
....
 
WHILE @@FETCH_STATUS = 0
BEGIN
	....
	set @PartQuantity = floor(@PartQuantity / @AUnitDivision) * @AUnitDivision;
	insert into #ListQuantity 
		(ConsignmentID, Quantity, BasicPrice, ConsignmentQuantity) 
	values 
		(@ConsignmentID, @PartQuantity, @BasicPrice, @ConsignmentQuantity)
	set @RemainQuantity = @RemainQuantity - @PartQuantity;
	FETCH NEXT FROM Consignment_Cursor INTO @ConsignmentQuantity, @ConsignmentID, @BasicPrice
 
END
CLOSE Consignment_Cursor
DEALLOCATE Consignment_Cursor

Таким образом floor отбрасывает дробную часть и мы получаем в ListQuantity 3181, 318 и 1. А вот эта единичка и зацикливает tsp_OfferingDistribute, т.к. значений три, а партий только две.

меняем floor на round и все работает

set @PartQuantity = round((@PartQuantity / @AUnitDivision),0) * @AUnitDivision;

В любом случае по методу Средневзвешенный списание происходит неверно и возникают неверные остатки. Поэтому видимо сменим метод.

Здравствуйте, Виктор!
Большое спасибо за активное участие. Учтем Ваши замечания

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