Ситуация, когда сервер «1С:Предприятия» внезапно начинает потреблять 100% ресурсов процессора, знакома многим администраторам и разработчикам. Особенно неприятно, если это происходит «вдруг» с отчетом, который раньше работал стабильно. Разберем по шагам, что происходит внутри системы в такие моменты, проанализируем логи технологического журнала и выясним, как оптимизировать код и серверную среду, чтобы избежать подобных коллапсов.
Первым делом при возникновении «полки» в 100% по CPU необходимо обратиться к Технологическому журналу (ТЖ). В рассматриваемом нами случае в логах фиксируются события SDBL. Давайте внимательно посмотрим на фрагмент записи:
44:37.498028-225250017,SDBL,3,process=rphost,p:processName=upp,OSThread=1660, ...
Func=insertRecords,tableName=#T30b7e819d3eb4efc8a6027d2e6e3ff3b,Sdbl='
INSERT #T30b7e819d3eb4efc8a6027d2e6e3ff3b
VALUES( ... ),
',Rows=1036551
Проанализируем ситуацию: событие insertRecords сообщает нам, что платформа пытается вставить данные во временную таблицу с именем #T.... Самое критичное здесь — параметр Rows=1036551. Это означает, что в запрос была передана внешняя ТаблицаЗначений, содержащая более миллиона строк. Платформа 1С вынуждена создать временную таблицу на стороне SQL-сервера и заполнить её всеми этими данными, прежде чем начать выполнение самого запроса.
Многие разработчики ошибочно полагают, что ТаблицаЗначений — это просто удобный способ передать данные в запрос. Однако при больших объемах данных включается механизм SDBL (System Database Layer), который работает следующим образом:
rphost должен подготовить данные из оперативной памяти, превратив их в поток команд для SQL-сервера. При миллионе строк это вызывает колоссальную нагрузку на CPU сервера приложений.INSERT) передается по сети (или через shared memory) на SQL-сервер.tempdb. Это нагружает как процессор, так и дисковую подсистему.Если такая операция выполняется в цикле или отчет запускается одновременно несколькими пользователями, сервер неизбежно «встает» на 100% загрузки.
Часто звучит вопрос: «Код не меняли полгода, почему зависло сегодня?». Выясним причину такого поведения. Существует несколько факторов, способных превратить старый отчет в «убийцу сервера»:
1. Параметрический нюх (Parameter Sniffing): SQL-сервер кэширует планы выполнения запросов. Если отчет был впервые запущен с небольшим набором данных, SQL-сервер запомнил оптимальный для малого объема план. Когда объем данных в ТаблицаЗначений вырос до миллиона, старый план стал неэффективным, что привело к деградации производительности.
2. Порог обновления статистики: В SQL-сервере существуют алгоритмы автоматического обновления статистики. Как только количество записей в физических таблицах базы данных (например, регистры накопления в УПП) пересекает определенный порог, SQL-сервер может кардинально изменить план запроса. Вместо быстрого поиска по индексу (Index Seek) он может выбрать полное сканирование таблицы (Index Scan), что резко повышает нагрузку на процессор.
3. Рост данных: Со временем количество документов в базе растет. То, что раньше выгружалось в 100 тысяч строк, сегодня может составлять миллион. Это та самая «точка перегиба», когда линейный рост данных приводит к экспоненциальному росту нагрузки.
Для решения проблемы рассмотрим правильный подход к разработке подобных отчетов. Основное правило: избегайте передачи больших таблиц значений в параметры запроса.
Вместо того чтобы сначала выгружать данные в ТаблицаЗначений, а потом передавать их обратно в запрос, как показано в примере ниже:
// ПЛОХОЙ ПРИМЕР
ТЗ = ПолучитьДанныеИзДругогоМеста(); // Здесь миллион строк
Запрос = Новый Запрос;
Запрос.Текст = "ВЫБРАТЬ * ИЗ &ВнешняяТЗ КАК ТЗ";
Запрос.УстановитьПараметр("ВнешняяТЗ", ТЗ);
Результат = Запрос.Выполнить();
Нужно стремиться к тому, чтобы все данные подготавливались внутри одного SQL-запроса с использованием временных таблиц. Разберем по шагам, как это сделать:
МенеджерВременныхТаблиц.ПОМЕСТИТЬ ВТ_Данные).ВТ_Данные с другими таблицами.Это позволит SQL-серверу работать с данными напрямую, без участия прослойки SDBL и лишней перегонки данных между rphost и SQL.
Иногда проблема кроется не только в коде, но и в настройках инфраструктуры. Фраза «админы что-то нашаманили» обычно означает выполнение регламентных или конфигурационных работ. Проанализируем ситуацию со стороны системного администрирования:
1. Настройка TempDB: Поскольку миллион строк вставляется во временную таблицу, огромная нагрузка ложится на базу tempdb. Убедитесь, что файлы tempdb вынесены на самые быстрые диски (NVMe SSD) и их количество соответствует количеству ядер процессора.
2. MAXDOP и Cost Threshold for Parallelism: Если Max Degree of Parallelism установлен в 0, SQL-сервер может попытаться выполнить тяжелый запрос на всех доступных ядрах, парализуя работу остальных пользователей. Рекомендуется устанавливать MAXDOP в значение от 1 до 4 (в зависимости от количества ядер) для серверов 1С.
3. Виртуализация и NUMA: Если 1С работает на виртуальной машине (VMware/Hyper-V), критически важно, чтобы конфигурация vCPU не пересекала границы физических NUMA-узлов. Если виртуальной машине выделено памяти или ядер больше, чем есть в одном физическом процессоре, задержки при обращении к памяти могут вызвать резкий рост CPU Ready и общей нагрузки.
4. Очистка процедурного кэша: Самый быстрый способ временно «вылечить» зависший отчет — выполнить команду DBCC FREEPROCCACHE. Это заставит SQL-сервер перестроить планы запросов, что часто помогает, если проблема была вызвана Parameter Sniffing.
Мы выяснили, что 100% загрузка процессора в 1С при выполнении отчетов чаще всего вызвана неэффективным взаимодействием сервера приложений и базы данных через механизм SDBL. Передача миллиона строк через ТаблицаЗначений является «антипаттерном» разработки. Для стабильной работы системы необходимо пересматривать алгоритмы в пользу пакетных запросов и следить за здоровьем tempdb и настройками параллелизма SQL-сервера.