Как исправить зависание закрытия месяца в 1С и переполнение базы TempDB на MS SQL Server?

Системный администратор 1С v8.3 (Управляемые формы) 1С:ERP Управление предприятием Налоговый учет IT и автоматизация бизнеса
← На главную

При выполнении регламентной процедуры закрытия месяца в крупных корпоративных базах данных на платформе 1С (таких как 1С:ERP Управление предприятием или 1С:Комплексная автоматизация) системные администраторы и разработчики часто сталкиваются с внезапным падением производительности. Процесс «зависает» на неопределенное время, а на сервере СУБД Microsoft SQL Server лавинообразно увеличивается размер базы данных tempdb, вплоть до полного исчерпания свободного места на диске. Выясним причину этой проблемы, детально проанализируем стек вызовов и структуру SQL-запроса, а также разберем по шагам эффективные методы ее устранения.

Анализ проблемы и стека вызовов

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


ОбщийМодуль.ДлительныеОперации.Модуль : 734 : ВыполнитьПроцедуру(ВсеПараметры.ИмяПроцедуры, ВсеПараметры.ПараметрыПроцедуры);
ОбщийМодуль.ДлительныеОперации.Модуль : 743 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяПроцедуры, ПараметрыПроцедуры);
ОбщийМодуль.ОбщегоНазначения.Модуль : 4856 : Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
: 1 : БухгалтерскиеОтчеты.ОпределитьСостояниеЭтаповРасчетаЗакрытияМесяца(Параметры[0],Параметры[1])
ОбщийМодуль.БухгалтерскиеОтчеты.Модуль : 1923 : Результат.СостоянияЭтапов = ЗакрытиеМесяцаСервер.ОпределитьСостояниеЭтаповРасчета(
ОбщийМодуль.ЗакрытиеМесяцаСервер.Модуль : 11293 : Обработки.ОперацииЗакрытияМесяца.ЗаполнитьСостоянияЭтапов(ПараметрыЗапускаОбновленияСостояния);
Обработка.ОперацииЗакрытияМесяца.МодульМенеджера : 526 : ПроверитьИспользованиеЭтапа(ПараметрыОбработчика);
Обработка.ОперацииЗакрытияМесяца.МодульМенеджера : 779 : ОбщегоНазначения.ВыполнитьМетодКонфигурации(
ОбщийМодуль.ОбщегоНазначения.Модуль : 4856 : Выполнить ИмяМетода + "(" + ПараметрыСтрока + ")";
: 1 : ЗакрытиеМесяцаСервер.Использование_НастройкаПоказателейДляРаспределенияРасходовНаСебестоимостьПродукции(Параметры[0])
ОбщийМодуль.ЗакрытиеМесяцаСервер.Модуль : 3435 : Документы.РаспределениеПрочихЗатрат.ИнициализироватьЗапросПолученияДанныхДляРаспределения(Запрос, ПараметрыЗапроса);
Документ.РаспределениеПрочихЗатрат.МодульМенеджера : 2269 : ПодготовитьСлужебныеТаблицы(Запрос.Параметры.КонецПериода,
Документ.РаспределениеПрочихЗатрат.МодульМенеджера : 3145 : НалоговыйУчет.ДоляТранспортныхРасходовТекущегоМесяца(Период, Организации, Запрос.МенеджерВременныхТаблиц);
ОбщийМодуль.НалоговыйУчет.Модуль : 6408 : Запрос.Выполнить();

Рассмотрим подробнее этот стек. Платформа пытается определить, нужно ли выполнять этап «Настройка показателей для распределения расходов на себестоимость продукции». Для этого вызывается служебный алгоритм налогового учета НалоговыйУчет.ДоляТранспортныхРасходовТекущегоМесяца, который рассчитывает долю транспортных расходов текущего периода в соответствии со ст. 320 НК РФ. Внутри этого метода выполняется сложный многострочный запрос СУБД, использующий конструкции UNION ALL и связывающий физические таблицы тяжелых регистров накопления с временными таблицами (такими как #tt37, #tt40, #tt189, #tt186).

Этот запрос обращается к основным таблицам движений и итогов регистров накопления:

Почему происходит лавинообразный рост TempDB?

Рассмотрим внутреннюю механику работы оптимизатора MS SQL Server в этой ситуации. База данных tempdb используется СУБД для хранения временных таблиц, созданных платформой 1С (префиксы #tt), а также для выполнения промежуточных операций сортировки (Sort), хэширования (Hash Match) и сохранения промежуточных результатов выполнения запросов.

Когда СУБД выполняет сложный запрос с множеством соединений, оптимизатор строит план выполнения на основе имеющейся статистики распределения данных в таблицах. Если статистика устарела или не актуализирована, происходит критическая ошибка оценки кардинальности (Cardinality Estimation):

  1. Оптимизатор полагает, что промежуточный шаг запроса или соединение с временной таблицей вернет всего 1 строку (вместо реальных сотен тысяч или миллионов строк).
  2. Исходя из этой неверной гипотезы, СУБД выбирает алгоритм соединения Nested Loops (вложенные циклы). Этот алгоритм эффективен только для единичных строк.
  3. Когда запрос начинает выполняться, СУБД сталкивается с реальным объемом данных. Ей приходится выполнять миллионы циклических чтений. Выделенной оперативной памяти (Memory Grant) под неверный план запроса катастрофически не хватает.
  4. В результате СУБД начинает сбрасывать промежуточные результаты вычислений на диск в базу данных tempdb (происходит так называемый Spill to Tempdb). Этот процесс лавинообразно забивает дисковую подсистему временными данными, увеличивая размер файлов tempdb.mdf и tempdb.ldf до тех пор, пока на физическом диске не закончится свободное место. Процесс закрытия месяца при этом полностью зависает.

Выясним, как устранить эту проблему и вернуть систему в штатный режим работы.

Решение 1: Актуализация статистики MS SQL Server (Рекомендуемый шаг)

Главная причина неоптимального плана запроса — неактуальная статистика. Стандартные регламентные операции обновления статистики СУБД со стандартным уровнем выборки могут пропускать изменения в таблицах итогов и движений регистров накопления 1С, особенно если в течение месяца проводились масштабные операции перепроведения документов.

Для исправления ситуации выполним принудительное обновление статистики с полным сканированием (FULLSCAN) для проблемных таблиц. Запустим в Среде управления SQL Server (SSMS) следующий сценарий:


-- Обновление статистики с полным сканированием для основной таблицы регистра
UPDATE STATISTICS dbo._AccumRg65591 WITH FULLSCAN, ALL;
-- Обновление статистики для таблицы итогов регистра
UPDATE STATISTICS dbo._AccumRgT65666 WITH FULLSCAN, ALL;
-- Также рекомендуется обновить статистику по второму задействованному регистру
UPDATE STATISTICS dbo._AccumRg65103 WITH FULLSCAN, ALL;
UPDATE STATISTICS dbo._AccumRgT65135 WITH FULLSCAN, ALL;

Использование параметра FULLSCAN гарантирует, что SQL Server проанализирует абсолютно все строки в таблицах, что позволит оптимизатору построить максимально точный и эффективный план выполнения запроса.

Решение 2: Сброс кэша планов запросов СУБД

Простое обновление статистики не всегда сразу решает проблему зависания, так как СУБД может продолжать использовать ранее скомпилированный «плохой» план запроса, который уже находится в кэше планов (Plan Cache). Чтобы принудительно заставить оптимизатор построить новый план с учетом обновленной статистики, выполним очистку кэша.

Чтобы не сбрасывать кэш планов для всего сервера целиком (что может временно снизить производительность других процессов), найдем и удалим конкретный проблемный план. Для этого выполним следующий скрипт в SSMS:


-- Поиск и удаление конкретного плана запроса из кэша по тексту запроса
DECLARE @PlanHandle VARBINARY(64);

SELECT TOP 1 @PlanHandle = deps.plan_handle
FROM sys.dm_exec_query_stats AS deps
CROSS APPLY sys.dm_exec_sql_text(deps.sql_handle) AS dept
WHERE dept.text LIKE '%_AccumRg65591%' AND dept.text LIKE '%#tt190%';

IF @PlanHandle IS NOT NULL
BEGIN
    DBCC FREEPROCCACHE (@PlanHandle);
    PRINT 'План запроса успешно удален из кэша.';
END
ELSE
BEGIN
    PRINT 'План запроса не найден в кэше.';
END

Если нет возможности точечно удалять планы, на тестовой или некритичной рабочей базе в период технологического окна можно выполнить полную очистку кэша планов командной:

DBCC FREEPROCCACHE;

Решение 3: Проверка и пересчет итогов в 1С

Если в базе данных 1С сдвинута граница рассчитанных итогов далеко в прошлое, платформа не сможет быстро получить остатки и обороты из оптимизированных таблиц итогов (таких как _AccumRgT65666). Платформа будет вынуждена делать ресурсоемкие выборки из основной таблицы движений за все периоды. Проверим и актуализируем итоги:

  1. Откроем информационную базу 1С в режиме «1С:Предприятие» от имени администратора.
  2. Перейдем в меню «Функции для технического специалиста» (или «Все функции») и выберем пункт «Управление итогами».
  3. Проверим состояние регистров накопления. Обратим особое внимание на регистры себестоимости и прочих расходов.
  4. Если период рассчитанных итогов отстает от текущего периода закрытия месяца, установим период итогов на текущий месяц и запустим процедуру расчета.
  5. При наличии признаков логического повреждения таблиц итогов, запустим в конфигураторе режим «Тестирование и исправление» (ТиИ) с установленным флагом «Пересчет итогов».

Решение 4: Оптимальная настройка TempDB на сервере СУБД

Чтобы исключить падение всей системы из-за переполнения диска файлами tempdb при выполнении тяжелых регламентных операций, системному администратору необходимо корректно настроить конфигурацию системной базы данных:

Решение 5: Использование трассировочных флагов и настроек СУБД

В современных версиях MS SQL Server (начиная с SQL Server 2014) разработчики СУБД изменили внутренний алгоритм оценки кардинальности (New Cardinality Estimator). Практика эксплуатации систем на платформе 1С показывает, что для сложных запросов со множеством временных таблиц старый алгоритм оценки работает стабильнее и реже строит катастрофически неоптимальные планы.

Для стабилизации планов запросов СУБД рекомендуется рассмотреть возможность использования следующих настроек:

  1. В свойствах рабочей базы данных на SQL Server в разделе Options установим параметр Legacy Cardinality Estimation в значение ON (для SQL Server 2016 и выше).
  2. Или задействуем глобальный трассировочный флаг 9481 на уровне всего экземпляра SQL Server, который принудительно включает старую версию оптимизатора для всех запросов.
  3. Применим глобальный трассировочный флаг 4199, который включает все исправления и микро-патчи оптимизатора запросов, выпущенные Microsoft после релиза вашей версии СУБД. Это помогает оптимизатору лучше справляться со специфическими запросами платформы 1С.

Выполнив указанные шаги по обслуживанию СУБД и оптимизации настроек платформы 1С, мы гарантированно избавимся от проблемы зависания закрытия месяца и предотвратим критический рост временных файлов базы данных tempdb.

← На главную