Как решить проблему лавинообразного роста tempdb при создании начального образа РИБ в 1С на MS SQL Server?

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

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

Представьте ситуацию: рабочая база данных имеет скромный размер около 2.5 ГБ, однако при попытке сформировать образ РИБ база tempdb разрастается до 70–80 ГБ, полностью забивает дисковое пространство, после чего СУБД аварийно завершает работу, а процесс создания образа прерывается. При этом тестирование и исправление (ТИИ) не выявляет никаких ошибок в структуре данных. Выясним, почему это происходит, и подробно разберем эффективные методы локализации и решения этой проблемы.

Почему переполняется tempdb при создании образа РИБ?

Для начала проанализируем внутренние механизмы СУБД и платформы «1С:Предприятие», которые приводят к подобному поведению системы:

  1. Использование механизма Snapshot Isolation (RCSI): В современных конфигурациях 1С по умолчанию включен режим блокировок Read Committed Snapshot Isolation. При создании начального образа запускается одна очень длинная транзакция на чтение. Если в этот момент в центральной базе продолжают работать пользователи или выполняются фоновые задания, SQL Server вынужден сохранять старые версии изменяемых данных в специальном хранилище версий (Version Store), которое физически находится именно в tempdb. Пока транзакция создания образа не завершится, эти версии строк не могут быть очищены, что вызывает лавинообразный рост дискового пространства.
  2. Неоптимальные запросы и декартовы произведения: При создании образа РИБ «по фильтру» платформа 1С генерирует сложные SQL-запросы, сопоставляя таблицы объектов с таблицами регистрации изменений. Если в коде конфигурации или правилах обмена присутствуют неоптимальные соединения таблиц без жестких ограничений (отборов), СУБД может формировать гигантские временные таблицы в tempdb. Например, перекрестное соединение крупных регистров без индексов способно моментально раздуть базу временных таблиц до десятков гигабайт.
  3. Устаревшая статистика базы данных: Если СУБД использует устаревшую статистику, оптимизатор SQL Server строит неверный план выполнения запроса. Вместо быстрого поиска по индексам он может применить ресурсоемкие операции сортировки (Sort) или хеширования (Hash Match), сбрасывая промежуточные результаты на диск в tempdb (так называемые Hash/Sort Spills).
  4. Циклические ссылки в иерархии: Наличие зацикливания в иерархических справочниках (когда элемент ссылается сам на себя или через цепочку соавторов) может приводить к бесконечной рекурсии при выгрузке данных платформой 1С, что вызывает бесконечное создание временных таблиц.
  5. Особенности старых версий платформы: На ранних релизах платформы 1С v8.3 (например, 8.3.9) механизмы создания РИБ были менее оптимизированы по сравнению с современными версиями, что приводило к избыточному дублированию данных во временных таблицах СУБД.

Шаг 1. Мониторинг и диагностика tempdb средствами SQL

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

Рассмотрим первый скрипт, который позволяет определить активные сессии, потребляющие наибольший объем дискового пространства в tempdb:


SELECT
    s.host_name,
    s.writes,
    usage.session_id,
    usage.user_objects_alloc_page_count,
    usage.user_objects_dealloc_page_count,
    usage.internal_objects_alloc_page_count,
    usage.internal_objects_dealloc_page_count
FROM
    sys.dm_db_session_space_usage usage
    LEFT JOIN sys.dm_exec_sessions s ON s.session_id = usage.session_id
ORDER BY
    (user_objects_alloc_page_count + internal_objects_alloc_page_count) DESC;

Этот запрос наглядно покажет нам ID сессии 1С, которая активно выделяет страницы (alloc page count) под пользовательские и внутренние объекты. Если мы обнаружим аномально высокие показатели, мы сможем сопоставить этот session_id с сеансом в консоли администрирования кластера 1С.

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


SELECT 
    obj.name AS Table_Name,
    SUM(ps.reserved_page_count) * 8 / 1024 AS Reserved_MB,
    SUM(used_page_count) * 8 / 1024 AS Total_MB,
    SUM(
        CASE
            WHEN (index_id < 2) THEN (in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count)
            ELSE lob_used_page_count + row_overflow_used_page_count
        END
    ) * 8 / 1024 AS Data_MB,
    SUM (
        CASE
            WHEN (index_id >= 2) THEN in_row_data_page_count + lob_used_page_count + row_overflow_used_page_count
            ELSE 0
        END
    ) * 8 / 1024 AS Index_MB,
    SUM(CASE WHEN (index_id < 2) THEN row_count ELSE 0 END) AS Rows_Count
FROM
    tempdb.sys.tables obj 
    LEFT JOIN tempdb.sys.dm_db_partition_stats ps ON ps.object_id = obj.object_id
GROUP BY
    obj.object_id, obj.name
ORDER BY
    Total_MB DESC;

Проанализировав результаты, мы поймем, создаются ли миллионы мелких таблиц, либо СУБД раздувает одну-две гигантские таблицы из-за отсутствия правильных условий соединения.

Шаг 2. Обновление статистики и очистка процедурного кэша

Часто СУБД строит неверный план выполнения из-за «залипшего» старого кэша планов запросов. Перед запуском процедуры создания начального образа РИБ обязательно выполним регламентные операции на уровне SQL-сервера.

Разберем последовательность действий:

  1. Запустим принудительное обновление статистики для всей рабочей базы данных, чтобы оптимизатор СУБД владел актуальной информацией о распределении данных: EXEC sp_updatestats;
  2. Очистим процедурный кэш, чтобы заставить SQL Server перестроить планы всех запросов заново с учетом новой статистики: DBCC FREEPROCCACHE;

Шаг 3. Временное отключение RCSI на период создания образа

Если во время выгрузки образа базы в ней параллельно работают другие пользователи, Version Store в tempdb неизбежно начнет расти. Самый простой способ избежать этого — выполнять создание образа РИБ в монопольном режиме, когда в базе нет активных транзакций, либо временно перевести базу в обычный режим блокировок (без версионирования строк).

Рассмотрим, как отключить версионирование строк перед процедурой:

  1. Переведем базу данных в однопользовательский режим, чтобы завершить все активные сессии: ALTER DATABASE [Имя_Вашей_Базы] SET SINGLE_USER WITH ROLLBACK IMMEDIATE;
  2. Отключим режим READ_COMMITTED_SNAPSHOT: ALTER DATABASE [Имя_Вашей_Базы] SET READ_COMMITTED_SNAPSHOT OFF;
  3. Вернем базу в многопользовательский режим: ALTER DATABASE [Имя_Вашей_Базы] SET MULTI_USER;
  4. Запустим процесс создания начального образа РИБ в 1С.
  5. После успешного завершения процесса вернем настройки базы данных в исходное состояние, повторив шаги и установив параметр в значение ON.

Шаг 4. Обходной путь создания РИБ через резервную копию (Backup/Restore)

Если штатный механизм платформы 1С СоздатьНачальныйОбраз() продолжает аварийно завершаться из-за нехватки дискового пространства под tempdb, мы можем прибегнуть к проверенному альтернативному сценарию создания подчиненного узла. Этот метод полностью исключает нагрузку на tempdb во время инициализации РИБ.

Разберем этот процесс по шагам:

  1. Создадим полную резервную копию (бэкап) центральной базы данных средствами MS SQL Server.
  2. Развернем эту резервную копию под новым именем на сервере СУБД (это и будет наша будущая подчиненная база).
  3. Подключимся к новой развернутой базе в режиме «Предприятие» монопольно. На данный момент она является точной копией центральной базы.
  4. Программно назначим эту базу подчиненным узлом РИБ. Для этого откроем внешнюю обработку и выполним следующий код на встроенном языке 1С:
    
    // Получим ссылку на узел, который должен стать главным для этой базы
    СсылкаНаГлавныйУзел = ПланыОбмена.ВашПланОбмена.НайтиПоКоду("КодЦентральногоУзла");
            
    Если ЗначениеЗаполнено(СсылкаНаГлавныйУзел) Тогда
        ПланыОбмена.УстановитьГлавныйУзел(СсылкаНаГлавныйУзел);
        Сообщить("База успешно преобразована в подчиненный узел РИБ.");
    Иначе
        Сообщить("Не удалось найти главный узел по указанному коду!");
    КонецЕсли;
    
  5. Поскольку мы развернули полную копию базы, в ней содержатся лишние данные, которые не должны находиться в подчиненном узле согласно установленным фильтрам РИБ. Запустим в этой базе групповую обработку удаления лишних объектов. Удаление будем производить небольшими порциями (транзакциями), чтобы не перегружать транзакционные логи и tempdb.

Этот метод гарантирует 100% результат даже на базах объемом в сотни гигабайт, поскольку исключает необходимость выполнения колоссальных по объему выборок данных за один проход.

Шаг 5. Правильное конфигурирование базы tempdb на сервере

Чтобы минимизировать риски падения СУБД при любых тяжелых операциях, важно правильно настроить саму базу данных tempdb на уровне операционной системы и MS SQL Server:

И наконец, обратим внимание на версию используемой технологической платформы. В старых релизах (таких как 8.3.9) присутствовали внутренние утечки памяти и неоптимальные алгоритмы работы с СУБД при выгрузке пакетов данных РИБ. Настоятельно рекомендуется обновить платформу «1С:Предприятие» до актуальных версий ветки 8.3.16 и выше, в которых разработчики 1С провели глобальную оптимизацию механизмов обмена данными и минимизировали использование временных таблиц при формировании начальных образов.

← На главную