Рассмотрим распространенную проблему, с которой сталкиваются разработчики при проектировании алгоритмов проведения документов в 1С. Ситуация выглядит следующим образом: при проведении документа база «зависает» в клиент-серверном варианте работы. При этом в файловой базе или на локальном сервере PostgreSQL этот же код выполняется без задержек.
Проанализируем типичный алгоритм, приводящий к такой проблеме. Документ формирует недостающие комплекты, списывает их (делает движения), а затем по новой методике проведения выполняет запрос к остаткам. Если обнаруживаются отрицательные остатки (ушли в минус), система устанавливает Отказ = Истина и осуществляет возврат. Именно в момент выхода из процедуры обработки проведения с отказом сервер 1С зависает.
При выходе из процедуры обработки проведения с установленным флагом Отказ = Истина платформа инициирует отмену (откат) транзакции. В файловом варианте транзакции реализуются на уровне внутренних блокировок файлов самой платформой 1С, поэтому откат происходит локально и очень быстро. В клиент-серверном же варианте 1С полностью делегирует управление транзакциями серверу СУБД (например, MS SQL Server).
В отличие от прямой записи данных, откат транзакции (Rollback) — это сложная и зачастую однопоточная операция для СУБД. Если алгоритм проведения генерирует большой объем движений (например, массивное списание или формирование множества комплектов), СУБД должна физически удалить эти вставленные данные и вернуть базу в исходное состояние, считывая информацию из журнала транзакций.
Откат может занимать в разы больше времени, чем сама запись. Сеанс пользователя визуально «зависает», ожидая ответа от сервера. Если дисковая подсистема, на которой лежит файл журнала транзакций (LDF), медленная или перегружена, возникают массовые ожидания на уровне СУБД, что полностью парализует текущую операцию.
Важно отметить различия между СУБД. В PostgreSQL используется архитектура многоверсионности (MVCC). При откате транзакции данные фактически не нужно «стирать» так же тяжело, как в MS SQL — версии строк просто помечаются как неактуальные. Этим объясняется то, что на локальном PostgreSQL подобное зависание может не воспроизводиться.
Методика «сначала всё записать в базу, потом запросом проверить остатки и откатить транзакцию, если минус» считается антипаттерном при больших объемах данных из-за огромных накладных расходов на СУБД. Выясним, как правильно переписать алгоритм.
Предварительный контроль («Старая» методика 1С)
Вместо того чтобы сначала формировать и записывать движения, применим следующий подход:
БлокировкаДанных.При таком подходе никаких тяжелых откатов физически записанных данных в СУБД не потребуется, так как при нехватке остатков мы просто устанавливаем отказ еще до начала ресурсоемких операций вставки.
Расчет в оперативной памяти
Альтернативный вариант — сформировать комплекты и будущие движения в виде таблиц значений (или структур коллекций) в оперативной памяти сервера 1С. Затем провести расчет на основе виртуальных таблиц остатков. И лишь в самом конце, если все проверки пройдены, загрузить эти коллекции в набор записей регистра, например в Движения.ТоварыНаСкладах.
Если изменить алгоритм быстро невозможно, или проблема проявляется даже при небольших объемах отменяемых данных, обратим внимание на настройки сервера баз данных.
Для точной диагностики на стороне 1С рекомендуем включить Технологический журнал и настроить сбор событий DBMSSQL, EXCP и TTIMEOUT. Это позволит точно увидеть, на каком именно SQL-запросе висит сервер во время выполнения возврата из обработки проведения.