Почему зависает закрытие месяца на операции корректировки стоимости номенклатуры и как это исправить?

Программист 1С v8.3 (Обычные формы) 1C:Бухгалтерия Бухгалтерский учет
← На главную

Зависание регламентной операции «Корректировка стоимости номенклатуры» — одна из самых коварных проблем в работе 1С:Предприятие в клиент-серверном варианте. Ситуация часто выглядит одинаково: в файловой базе месяц закрывается за считанные минуты, а на мощном SQL-сервере процесс может длиться часами или вовсе «уходить в бесконечность». В этой статье мы подробно разберем, почему это происходит, и проанализируем пошаговые методы решения проблемы: от простых манипуляций с базой до глубокой оптимизации программного кода.

Выясняем причину: почему SQL-сервер «задумывается»

Проанализируем механику работы операции. Корректировка стоимости — это сложный алгоритм, который пересчитывает себестоимость списания с учетом всех поступлений и перемещений за период. Основная нагрузка ложится на запросы к регистрам бухгалтерии (Хозрасчетный) и накопления (ПартииТоваровНаСкладах). Когда мы сталкиваемся с тем, что в консоли запросов всё работает быстро, а при выполнении кода — виснет, причина чаще всего кроется в неудачном плане запроса, который строит оптимизатор MS SQL Server.

Рассмотрим подробнее основные факторы:

  1. Parameter Sniffing: SQL-сервер кэширует план выполнения на основе первых переданных параметров. Если параметры следующего запроса сильно отличаются, старый план становится неэффективным.
  2. Использование иерархии в виртуальных таблицах: Конструкция В ИЕРАРХИИ внутри параметров виртуальной таблицы заставляет SQL выполнять тяжелые вложенные сканирования.
  3. Кольцевые ссылки: Если в данных есть зацикливание (например, Комплект А состоит из Номенклатуры Б, которая в свою очередь входит в Комплект А), алгоритм может зациклиться.

Решение 1. Очистка кэша и регламентные операции SQL

Прежде чем менять код, попробуем «встряхнуть» SQL-сервер. Часто проблема решается простой очисткой процедурного кэша и обновлением статистик. Если после выгрузки в .dt и обратной загрузки месяц закрывается один раз нормально, а потом снова виснет — это явный признак проблем со статистикой таблиц.

Выполним следующие команды в SQL Management Studio для вашей базы данных:


-- Очистка кэша планов выполнения
DBCC FREEPROCCACHE;
DBCC FREESESSIONCACHE;
DBCC FREESYSTEMCACHE ('ALL');
DBCC DROPCLEANBUFFERS;
GO

-- Обновление статистик с полным сканированием
UPDATE STATISTICS [ИмяТаблицыРегистраБухгалтерии] WITH FULLSCAN;

Разберем, что это дает: эти команды заставляют сервер забыть старые неоптимальные планы и собрать актуальную информацию о распределении данных в таблицах. Это позволяет СУБД построить новый, более быстрый план выполнения запроса.

Решение 2. Оптимизация тяжелых запросов в конфигурации

Если стандартные средства SQL не помогают, перейдем к анализу программного кода. Проанализируем процедуру ПолучитьТаблицуПеремещений или ПолучитьТаблицуОперацийСписания в общем модуле КорректировкаСтоимости. Одной из критических ошибок является использование больших списков счетов с проверкой иерархии прямо в параметрах виртуальной таблицы.

Рассмотрим пример того, как нельзя оставлять запрос:


Запрос.Текст = "ВЫБРАТЬ ... 
|ИЗ РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(&ДатаНач, &ДатаКон, , 
| СчетДт В ИЕРАРХИИ (&СписокСчетов), , 
| СчетКт В ИЕРАРХИИ (&СписокСчетов), , ...) КАК ХозрасчетныйОбороты";

Перепишем этот фрагмент, используя временные таблицы. Это «разгрузит» оптимизатор SQL и позволит ему четко понять объем выборки. Разберем по шагам:

  1. Выгрузим все счета (включая подчиненные) во временную таблицу.
  2. Проиндексируем её.
  3. Используем её в основном запросе.

// Сначала подготовим список всех счетов с учетом иерархии
Запрос.Текст = "ВЫБРАТЬ
|   Хозрасчетный.Ссылка КАК Ссылка
|ПОМЕСТИТЬ ВТ_Счета
|ИЗ
|   ПланСчетов.Хозрасчетный КАК Хозрасчетный
|ГДЕ
|   Хозрасчетный.Ссылка В ИЕРАРХИИ(&СписокСчетов)
|
|ИНДЕКСИРОВАТЬ ПО
|   Ссылка;
|////////////////////////////////////////////////////////////////////////////////
|ВЫБРАТЬ ...
|ИЗ
|   РегистрБухгалтерии.Хозрасчетный.ОборотыДтКт(&ДатаНач, &ДатаКон, , 
|       СчетДт В (ВЫБРАТЬ Ссылка ИЗ ВТ_Счета), , 
|       СчетКт В (ВЫБРАТЬ Ссылка ИЗ ВТ_Счета), , ...) КАК ХозрасчетныйОбороты";

Такой подход гарантирует, что SQL-сервер сначала определит конкретный список идентификаторов счетов и только потом пойдет искать обороты по ним, что значительно ускоряет выполнение в режиме клиент-сервер.

Решение 3. Обработка специфических данных (Комплекты и NULL)

Иногда зависание вызвано некорректной работой с типами данных в массивах. В некоторых релизах конфигураций была замечена проблема, когда игры с типом NULL приводили к разнице в поведении файловой и серверной баз. Посмотрим на пример исправления в процедуре ОцифроватьСостояния:


// Вместо создания пустого массива с типом NULL
// Массив = Новый Массив;
// Массив.Добавить(Тип("NULL"));

// Используем явное описание типов из колонок таблицы
Массив = Таб.Колонки[2].ТипЗначения.Типы(); 
Массив.Добавить(Тип("NULL"));
ОписаниеТиповС = Новый ОписаниеТипов(Массив);

Также важно проверить наличие «зацикливания» в спецификациях и комплектации. Если отладчик зависает на итерации по массиву комплектов, попробуйте проанализировать структуру МассивКомплектов. Если в нем бесконечно прибавляются элементы, значит, в справочнике Номенклатура или Спецификации допущена логическая ошибка: товар является составной частью самого себя.

Решение 4. Технические настройки платформы и сервера

Если вы используете старые версии платформы (например, 8.2.15), крайне рекомендуем выполнить переход на актуальные релизы 8.3. В новых версиях существенно переработан механизм трансляции запросов к СУБД. Кроме того, рассмотрим настройки самого SQL-сервера:

  1. MAXDOP (Max Degree of Parallelism): Установите значение 1. Это запретит SQL-серверу пытаться выполнять один тяжелый запрос в несколько потоков, что в 1С часто приводит к блокировкам CXPACKET и зависаниям.
  2. RCSI (Read Committed Snapshot Isolation): Включите этот режим для базы. Он позволит процедуре корректировки читать данные, не дожидаясь окончания других транзакций, и наоборот.
  3. TempDB: Убедитесь, что база tempdb вынесена на быстрый диск (SSD). Корректировка активно использует временные таблицы, и медленный tempdb может стать «бутылочным горлышком».

Итоги и рекомендации

Подведем итог: если закрытие месяца виснет на корректировке стоимости, не спешите сразу переписывать код. Сначала выполните тестирование и исправление в конфигураторе и очистку кэша SQL. Если это помогает лишь временно — переходите к оптимизации запросов, избавляясь от конструкции В ИЕРАРХИИ внутри виртуальных таблиц. Совокупность технических настроек сервера (MAXDOP) и грамотного написания запросов позволяет сократить время закрытия месяца с нескольких часов до нескольких минут.

← На главную