При работе в конфигурации 1С:Предприятие 7.7 «Торговля и Склад» (ТиС) на сервере баз данных MS SQL Server 2008 пользователи часто сталкиваются с существенным замедлением проведения объемных расходных накладных (по 200–500 строк). Проблема многократно усиливается при активном списании партий в режиме реального времени. Разберем детально, почему возникает просадка производительности, как организовать разделение на оперативное и регламентное проведение по расписанию, а также как кардинально ускорить расчет партий с помощью современных методов оптимизации.
Чтобы найти правильное решение, проанализируем внутреннюю архитектуру типовой конфигурации «Торговля и Склад» редакции 9.2 и особенности работы платформы 1С 7.7 с СУБД:
РасходнаяНакладная в процедуре ОбработкаПроведения() перебирает каждую строку табличной части. Для каждого товара инициируется отдельное обращение к регистру ПартииНаличие и ПартииОтданные. Для накладной из 300 строк платформа генерирует сотни вложенных SQL-запросов внутри одной открытой транзакции, создавая массивную нагрузку на сеть и сервер._1SJOURN, из-за чего несколько менеджеров не могут одновременно проводить крупные документы.Рассмотрим вариант разделения учета: днем накладные проводятся только по количественным остаткам (или без расчета партий), а ночью регламентный процесс последовательно рассчитывает себестоимость и движения по партиям за прошедший день.
Разберем по шагам, как настроить автоматический запуск перепроведения с помощью системного планировщика задач (Task Scheduler), командной строки и внешней компоненты FormEx.
Передача параметров через командную строку. Создадим в планировщике Windows задание, запускающее 1С под специальным системным пользователем с передачей флага автоматической обработки:
Команда запуска:
"C:\Program Files (x86)\1Cv77\BIN\1cv7s.exe" enterprise /D"\\Server\1CBase\" /N"RobotNight" /P"SecretPass" /PRM"NightPosting"
Обработка параметров в глобальном модуле. В процедуре ПриНачалеРаботыСистемы() считываем переданный параметр с помощью метода компоненты FormEx:
Процедура ПриНачалеРаботыСистемы()
// Загрузка внешней компоненты FormEx для работы с параметрами
Если ЗагрузитьВнешнююКомпоненту("FormEx.dll") = 0 Тогда
Сообщить("Не удалось загрузить FormEx.dll!", "!");
КонецЕсли;
Сервис = СоздатьОбъект("Сервис");
ПараметрЗапуска = Сервис.ПараметрЗапуска;
Если ВРег(СокрЛП(ПараметрЗапуска)) = "NIGHTPOSTING" Тогда
// Запуск регламентной обработки
ОткрытьФорму("Обработка.АвтоПерепроведениеПартий", 1);
КонецЕсли;
КонецПроцедуры
Алгоритм регламентной обработки перепроведения. В модуле формы созданной обработки реализуем выборку документов за текущий день и их неоперативное перепроведение с полным расчетом партий:
Процедура АвтоматическийПересчет()
Перем Док;
ДатаНачала = ТекущаяДата();
ДатаОкончания = ТекущаяДата();
Док = СоздатьОбъект("Документ.РасходнаяНакладная");
Док.ВыбратьДокументы(ДатаНачала, ДатаОкончания);
Пока Док.ПолучитьДокумент() = 1 Цикл
Если Док.Проведен() = 1 Тогда
Попытка
// Устанавливаем флаг проведения по партиям в контексте
глФлагПолногоСписанияПартий = 1;
// Перепроводим документ
Док.Провести(1, "");
глФлагПолногоСписанияПартий = 0;
Исключение
Сообщить("Ошибка проведения документа: " + Док.ТекущийДокумент() + " - " + ОписаниеОшибки());
КонецПопытки;
КонецЕсли;
КонецЦикла;
// Завершаем сеанс робота
ЗавершитьРаботуСистемы(0);
КонецПроцедуры
Перепроведение ночью решает проблему дневных задержек, но создает риск неактуальной себестоимости в течение рабочего дня. Наиболее эффективным подходом является оптимизация проведения в реальном времени с применением внешней компоненты 1С++ и прямых SQL-запросов (ODBCRecordset).
Рассмотрим, как заменить построчные запросы к регистру одним пакетным запросом:
Регистр.ПартииНаличие.Остаток(...) в цикле по строкам формируем один SQL-запрос, выбирающий все свободные партии для всей номенклатуры документа разом.ИндексированнаяТаблица или ТаблицаЗначений. Алгоритм списания (FIFO или LIFO) выполняется в памяти за доли секунды.Пример фрагмента запроса через ODBCRecordset для получения остатков партий по списку номенклатуры:
// Создание объекта прямого доступа к базе SQL
RS = СоздатьОбъект("ODBCRecordset");
ТекстЗапроса = "
|SELECT
| $Рег.Номенклатура as [Номенклатура $Справочник.Номенклатура],
| $Рег.Партия as [Партия $Справочник.Партии],
| $Рег.ОстатокТовара as КоличествоОстаток,
| $Рег.Стоимость as СтоимостьОстаток
|FROM
| $РегистрОстатки.ПартииНаличие(:ВыбДата~, ,
| Номенклатура IN (SELECT Val FROM #СписокТоваров),
| (Номенклатура, Партия),
| (ОстатокТовара, Стоимость)) as Рег
|ORDER BY
| $Рег.Номенклатура,
| $СпрП.ДатаДок ASC
|";
RS.УложитьТаблицу(ТЗТоварыДокумента, "#СписокТоваров");
ТаблицаПартий = RS.ВыполнитьИнструкцию(ТекстЗапроса);
Проанализируем обязательные сервисные действия на уровне базы данных и SQL-сервера, которые устраняют скрытые торможения 1С 7.7:
Compatibility Level (рекомендуется режим 80 или 90 для исключения некорректных планов выполнения вложенных запросов платформы).— Регулярное обновление статистик базы данных (UPDATE STATISTICS WITH FULLSCAN).
— Еженедельная дефрагментация и реиндексация таблиц (ALTER INDEX ALL REBUILD).
— Размещение базы tempdb на быстрых NVMe/SSD накопителях с разделением на несколько файлов данных по количеству ядер CPU.
Комбинация очистки итогов, автоматического ночного расчета либо внедрения прямых запросов позволяет полностью ликвидировать задержки при проведении расходных документов любого объема.