948 секунд против 66: что делать, когда висит отчет, и как перестать гадать

16.10.26

База данных - Технологический журнал

Составной отчет формировался 15 минут. Вместо перебора разделов одна команда rac показала, что сеанс занят запросом к СУБД, а временный техжурнал с порогом 20 секунд за один прогон назвал виновника: один SQL на 240 секунд и точную строку модуля. В статье четыре разные картины «висит» и как их различить: идет запрос в СУБД, клиент ждет невидимое модальное окно, зомби-вызов после закрытого клиента, зависшее фоновое задание. Пример logcfg.xml, разбор события DBMSSQL с полем Context, замер пакета запросов по временным таблицам, регламентное задание, которое «выполнено», а данные стоят, и шпаргалка по диагностике.

UPD 23.10.2026. Исправлены единицы порога в фильтре техжурнала: в logcfg.xml свойство duration задается в сотнях микросекунд, 20 секунд это value="200000". Подробности в разделе про техжурнал. Спасибо triviumfan за поправку.

«Висит»: четыре разные картины на сервере

Составной отчет, наш обзор сезона, формировался 15 минут. Он собирает данные из других отчетов блока через одну функцию ТаблицаОтчета(...), и первое желание было понятным: отключать разделы по одному и смотреть, какой тормозит. Это долго и ничего не гарантирует. Вместо этого rac показал, что сеанс занят запросом к СУБД, а техжурнал с порогом длительности за один прогон назвал виновника: один SQL на 240 секунд и точную строку модуля, откуда он пришел. После переписывания одного вложенного отчета обзор стал собираться за 66 секунд вместо 948.

В статье «89 минут против 6: реструктуризация большой серверной базы» rac и опознание своих rphost были вспомогательным шагом. Здесь с них все начинается.

Стенд: 1С:Бухгалтерия предприятия КОРП 3.0, платформа 8.5.1, серверная база на MSSQL. На машине несколько кластеров разных версий.

Первый шаг: rac session list

Слово «висит» описывает четыре разных состояния: сервер выполняет запрос, сервер ничего не делает и ждет клиента, клиента уже нет, а вызов идет, или мешает фоновое задание. Лечатся они по-разному, и одна команда отделяет их друг от друга.

У нашего кластера 8.5 служба RAS постоянно не запущена, поэтому поднимаем ее на время. Версия ras и rac должна совпадать с версией кластера: RAS соседнего кластера другой версии тут не поможет.

$bin = "C:\Program Files\1cv8\8.5.1.1507\bin"

Start-Process "$bin\ras.exe" -ArgumentList 'cluster','--port=5545','localhost:5540' -WindowStyle Hidden

& "$bin\rac.exe" cluster list localhost:5545

& "$bin\rac.exe" session list --cluster=<uuid> localhost:5545

Если у кластера заведен администратор, добавьте --cluster-user и --cluster-pwd. Из длинного вывода по сеансу нужны несколько полей. Вот одна из сессий того дня:

session-id            : 63

calls-all             : 78

db-proc-info          : "56"

duration-all-dbms     : 261347

duration-current      : 391235

duration-current-dbms : 129172

cpu-time-current      : 1484

Время в миллисекундах. duration-current показывает, сколько длится текущий серверный вызов (здесь 391 секунда), duration-current-dbms сколько длится текущее обращение к СУБД внутри него (129 секунд). db-proc-info дает номер соединения на SQL Server, тот же dbpid потом встретится в техжурнале. Если оба времени растут от замера к замеру, сервер занят запросом, и дальше нужен техжурнал.

Неприятная деталь, которая объясняет «сервер тормозит у всех»: когда клиент отваливается по таймауту или его закрывают, вызов на сервере продолжает выполняться. Это не зависание, это тот же долгий SQL, только без получателя. Пользователь не дождался, запустил отчет снова и добавил второй такой же вызов. В нашем списке было несколько сессий с duration-current около шести минут одновременно. Снимать такие сеансы можно штатно, через rac session terminate или консоль кластера, но сначала убедитесь, что это действительно ваш отчет, а не чья-то проводка.

И еще одна проверка, на которой легко потерять час: при нескольких кластерах на машине загрузка процессора rphost ничего не значит, пока вы не опознали свои процессы по версии платформы в пути и порту -regport. Команда для этого есть в предыдущей статье.

Техжурнал с порогом: текст SQL и строка BSL

Прямого доступа к SQL Server у нас на стенде не было: под Windows-учеткой sqlcmd не пускал, представления DMV недоступны. Техжурнал оказался не запасным путем, а единственным, и при этом лучшим: в нем есть то, чего DMV не покажут, стек вызовов BSL.

Делаем копию logcfg.xml в каталоге bin\conf нужной версии платформы и добавляем к существующей конфигурации отдельный временный журнал:

<log location="D:\1C_TJ_SQL" history="24">

  <event>

    <eq property="name" value="DBMSSQL"/>

    <gt property="duration" value="200000"/>

  </event>

  <event>

    <eq property="name" value="SDBL"/>

    <gt property="duration" value="200000"/>

  </event>

  <property name="all"/>

</log>

Длительность в микросекундах, 20 000 000 означает 20 секунд.

UPD 23.10.2026, исправление. В фильтре logcfg.xml свойство duration задается в сотнях микросекунд, поэтому 20 секунд это value="200000". Для микросекунд есть отдельное свойство durationus. А в самой строке журнала длительность пишется в микросекундах (-239572998 ниже это 240 секунд), отсюда и наша путаница. Ошибку нашел в комментариях triviumfan, спасибо. Мы перепроверили по протоколу той диагностики: с порогом 20000000, то есть 2000 секунд, журнал за 11 минут работы отчета не записал ни одного события, а виновника поймал порог 1000000, то есть 100 секунд.

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

Мелочь, на которой можно споткнуться: если править файл из bash через heredoc, последовательность \1 в пути D:\1C_TJ_SQL превращается в управляющий символ, и журнал молча пишет непонятно куда. Правьте через PowerShell ([IO.File]::WriteAllText) и перечитывайте результат. После диагностики верните файл из копии.

Запустили отчет, дождались, открыли журнал rphost. Событие выглядело так (сокращено):

11:26.787000-239572998,DBMSSQL,4,level=DEBUG,process=rphost,...,AppID=1CV8C,...,Trans=0,dbpid=56,Sql='SELECT

...

FROM (SELECT DISTINCT

(CAST(DATEPART(YEAR, T2._Fld48141) AS NUMERIC(4)) - 2000) AS Q_001_F_000_

FROM dbo._AccumRg48136 T2 WHERE ...) T1

INNER JOIN (SELECT DISTINCT ... FROM dbo._AccumRg48136 T4 ...) T3

ON 1=1

LEFT OUTER JOIN (SELECT ... GROUP BY (CAST(DATEPART(YEAR, T7._Fld48141) ...) T6

ON (T1.Q_001_F_000_ = T6.Q_001_F_000_) AND ...

',Rows=14,RowsAffected=-1,Context='...

  Отчет.<Обзор>.МодульМенеджера : 1861 : Дан.Вставить("РаботыПоСадам", ТаблицаОтчета("<ОтчетПоРаботам>", ...));

    Отчет.<Обзор>.МодульМенеджера : 633 : Вывод.Вывести(Процессор);'

Число после дефиса в начале строки и есть длительность: 239 572 998 микросекунд, почти 240 секунд. Поле Context дает стек до строки: обзор, строка 1861, вызов ТаблицаОтчета для конкретного вложенного отчета. Следующее событие в журнале пришло со строки 1862, тот же отчет в другом разрезе, еще 244 секунды. Перебором разделов мы бы это искали долго.

По тексту SQL видна и причина. Вложенный отчет считал год через ГОД(День) и соединял «все годы» со «всеми ключами» (ON 1=1), а затем с подзапросом агрегатов по выражению от даты, без временной таблицы. Результат 14 строк, а работы на четыре минуты. Запрос переписали на временные таблицы с отбором по дате, и обзор целиком ускорился с 948 до 66 секунд.

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

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

Части = СтрРазделить(ТекстПакета, ";");

МВТ = Новый МенеджерВременныхТаблиц;

Лог = Новый Массив;

Для Каждого Часть Из Части Цикл

    Если ПустаяСтрока(Часть) Тогда Продолжить; КонецЕсли;

    Запрос = Новый Запрос(Часть);

    Запрос.МенеджерВременныхТаблиц = МВТ;

    Запрос.УстановитьПараметр("НачалоПериода", НачалоПериода);

    Запрос.УстановитьПараметр("КонецПериода", КонецПериода);

    Т0 = ТекущаяУниверсальнаяДатаВМиллисекундах();

    Имя = "";

    Поз = СтрНайти(Часть, "ПОМЕСТИТЬ ");

    Если Поз > 0 Тогда Имя = СтрПолучитьСтроку(СокрЛП(Сред(Часть, Поз + 10, 40)), 1); КонецЕсли;

    Попытка

        Запрос.Выполнить();

        Лог.Добавить(Имя + ": " + (ТекущаяУниверсальнаяДатаВМиллисекундах() - Т0) + " мс");

    Исключение

        Лог.Добавить(Имя + ": ОШИБКА " + КраткоеПредставлениеОшибки(ИнформацияОбОшибке()));

    КонецПопытки;

КонецЦикла;

Разрезать пакет по ; грубо: точка с запятой внутри комментария или строкового литерала ломает разбор, и у меня последние части упали с «Ожидается выражение ВЫБРАТЬ». Для замера это не помешало, медленный шаг стоял раньше.

Пакет из 15 временных таблиц: где уходит время

Наш отчет контроля данных на тестовой базе формировался около пяти минут (в одном из прогонов только этот шаг занял шесть). Замер показал, что 14 временных таблиц из 15 вместе укладываются в 0,76 секунды, а одна занимает 365. Это было соединение с регистром состояний по условию на период, без предварительного сужения. Решение стандартное: сначала отобрать в индексированную временную таблицу нужные ключи за период, потом соединять с регистром по ним. Отдельно заменили соединения с табличными частями документов по нетипизированным полям на индексированные временные таблицы. После этого отчет на той же базе стал собираться за секунды.

Сервер простаивает, а клиент ждет

Обратная картина. Мы прогоняем отчеты скриптом: тонкий клиент запускается с /Execute и внешней обработкой, которая выполняет код и пишет результат в файл. Однажды такой прогон обзора дважды «висел» по 50 минут. В rac у сеанса duration-current = 0, текущего вызова нет, процессор rphost не растет, файл результата не появляется.

Причина была на экране клиента, который никто не видел: модальное окно «Ошибка инициализации модуля... Слишком много фактических параметров». В модуле менеджера вызов собственной функции передавал 8 аргументов, а параметров у нее 7. Проверка ошибок проекта в EDT эту ошибку не показала, и она доехала до базы. Клиент ждал, пока закроют окно, скрипт ждал клиента до таймаута, и снаружи это выглядело как очень долгий запрос.

Вывод простой: если «висит», а у сервера нет текущего вызова, ждать бесполезно. Снимайте клиент, смотрите на окно, ищите ошибку компиляции или исключение. При изменении числа аргументов сверяйте вызовы с сигнатурой вручную.

Там же рядом второй ложный след скриптового прогона. Внешняя обработка, запущенная пользователем без права «Администрирование», работает в безопасном режиме, и фоновое задание из нее его наследует. Привилегированный модуль там привилегий не поднимает, и вы получаете «Нарушение прав доступа» в коде, который интерактивно работает. Все, что зависит от привилегированного режима, проверяйте в настоящей форме под тестовым пользователем.

Фоновые и регламентные задания

Задание висит и держит базу. Регламентное «Извлечение текста» из БСП, которое запускается каждые 85 секунд, однажды встало внутри извлечения файла с открытой транзакцией. Соединение с SQL у этого сеанса «спало» двое с половиной суток, а на третий день задание не дало обновить конфигурацию. rac session terminate вызов не снял. Помог только перезапуск rphost в окно без пользователей. Перед таким перезапуском посмотрите, кто еще работает в этом процессе: там может оказаться чей-то конфигуратор.

Разбор показал, что полнотекстовый индекс в базе ни разу не строился, а примерно у 1 900 файлов из 4 852 текст «извлечь не удалось». Задание выключили, включать его обратно будем только вместе с построением индекса. На время обновления регламентные задания можно запретить штатно:

rac infobase update --cluster=<uuid> --infobase=<uuid> --infobase-user=<user> --infobase-pwd=<pwd> --scheduled-jobs-deny=on localhost:5545

После обновления верните off.

Задание «выполнено», а данные стоят. Регламентная загрузка из внешней SQL-базы на рабочей базе не двигалась шесть дней. Первая причина: в расписании, выставленном через форму, остался пустой «повторять каждые ... дней», то есть ПериодПовтораДней = 0. Повтор в течение дня работает только в день установки, со следующего дня задание не стартует вообще, без ошибок и без записей в журнале. Проверяйте оба поля: ПериодПовтораДней = 1 и нужный ПериодПовтораВТечениеДня.

Историю запусков смотрите с отбором по имени метода:

Задания = ФоновыеЗадания.ПолучитьФоновыеЗадания(

    Новый Структура("ИмяМетода", "<Модуль>.<Метод>"));

Отбор по ИдентификаторРегламентногоЗадания, переданному строкой, платформа проигнорировала и отдала всю историю базы.

Вторая причина вскрылась после починки расписания: задание пошло каждые полчаса, данные частично поступали, а состояние загрузки стояло. Формат(0, "ЧГ=0") возвращает пустую строку, и условие "... > " + Формат(Счетчик, "ЧГ=0") превращалось в WHERE ... > ORDER BY. Исключение ловилось внутри процедуры загрузки и писалось в журнал, а фоновое задание завершалось успешно. История фоновых заданий в таком случае честно говорит «Задание выполнено». Правду знает журнал регистрации:

ТЗ = Новый ТаблицаЗначений;

Отбор = Новый Структура("Событие", "<ИмяСобытияЗагрузки>");

ВыгрузитьЖурналРегистрации(ТЗ, Отбор);

// колонка уровня называется Уровень

Числа в текст запроса к внешней базе теперь подставляем только через функцию с форматом "ЧГ=0; ЧН=0".

Шпаргалка

Симптом Что смотреть Вывод
Отчет формируется минутами rac session list: растут duration-current и duration-current-dbms Долгий запрос, нужен техжурнал
Сервер нагружен, а пользователь отчет уже закрыл сеанс с долгим duration-current без живого клиента Зомби-вызов, повтор отчета добавит еще один
«Висит», но rphost без нагрузки duration-current = 0, текущего вызова нет Окно ошибки или ожидание в клиенте
Нагрузка на rphost есть, но непонятно чья версия в пути процесса и -regport Возможно, чужой кластер
Отчет на СКД с длинным пакетом замер каждой временной таблицы Один шаг обычно забирает почти все время
Обновление конфигурации не идет фоновые сеансы в rac, долгий вызов Зависшее задание держит транзакцию
Задание включено, данных нет ПериодПовтораДней, история по ИмяМетода Задание не стартует
Задание «выполнено», данных нет журнал регистрации по событию Исключение поймано внутри кода

Чеклист, в порядке от дешевого к дорогому:

  1. Поднять RAS нужной версии и снять rac session list два раза с интервалом.
  2. Определить картину: запрос в СУБД, ожидание клиента, вызов без клиента или фоновое задание.
  3. Для запроса: временный техжурнал DBMSSQL и SDBL с порогом 20 секунд, один прогон, поля Sql и Context.
  4. Для пакета на СКД: замер по временным таблицам.
  5. Для простаивающего сервера: окно в клиенте, ошибка компиляции, число аргументов.
  6. Для задания: расписание, история по имени метода, журнал регистрации.
  7. Вернуть logcfg.xml из копии и остановить временный RAS.

Сеансы снимаем только штатно, через rac или консоль кластера, и только когда понятно, что именно снимаем. Соединения на стороне SQL Server в обход платформы не трогаем: так легко оставить базу в непредсказуемом состоянии.

Главное, что изменилось в моей работе после этих случаев: вопрос «что тормозит» я больше не задаю коду. Сначала спрашиваю сервер, занят ли он вообще, и только потом читаю модули. Ответ «не занят» сразу уводит поиск от запросов: к клиенту, к расписанию, к журналу регистрации. Ответ «занят» за один прогон с техжурналом дает строку модуля.

Если у вас был зависший отчет, который не укладывается ни в одну из этих четырех картин, опишите его в комментариях: платформа, СУБД, что показали rac и техжурнал. Особенно интересны случаи с управляемыми блокировками и TLOCK, до них в этой истории дело так и не дошло.

Вступайте в нашу телеграмм-группу Инфостарт

техжурнал logcfg.xml rac session list DBMSSQL SDBL производительность медленный отчет зависание временные таблицы регламентное задание журнал регистрации СКД

Вы можете заказать платную адаптацию этой статьи под ваши задачи на «Бирже заказов».

  • 0% комиссии — оплата напрямую исполнителю;
  • Исполнители любого масштаба — от отдельных специалистов до команд под проект;
  • Прямой обмен контактами между заказчиком и исполнителем;
  • Безопасная сделка — при необходимости;
  • Рейтинги, кейсы и прозрачная система откликов.

См. также

Инструментарий разработчика Роли и права Запросы СКД Разработчик Руководитель проекта 1С:Предприятие 8 Платные (руб)

Инструменты для разработчиков 1С 8.3 и 8.5: Infostart Toolkit. Автоматизация и ускорение разработки на управляемых формах. Легкость работы с 1С.

16500 руб.

02.09.2020    286100    1608    423    

1220

Сервера Системный администратор Разработчик 1С 8.3 Абонемент ($m)

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

1 стартмани

16.02.2026    9409    131    sapervodichka    31    

94

Администрирование веб-серверов Сервера Нейросети Разработчик Платные (руб)

Сервер поиска по метаданным и поиска по коду, Сервер экспорта и поиска по документации, Сервер синтаксической проверки кода

17.06.2025    17039    0    Infostart    20    

113

Инструментарий разработчика Запросы Разработчик 1С:Предприятие 8 1С:Зарплата и кадры государственного учреждения 3 1С:Зарплата и Управление Персоналом 3.x Абонемент ($m)

QueryConsole1C — расширение, включающее консоль запросов с поддержкой исполняемых представлений — аналогов виртуальных таблиц, основанных на методах программного интерфейса ЗУП. Оно позволяет выполнять запросы с учётом встроенной бизнес-логики, отлаживать алгоритмы получения данных и автоматически генерировать код на встроенном языке 1С.

1 стартмани

16.05.2025    13721    168    zup_dev    32    

87

Сервера Системный администратор Бесплатно (free)

На первый взгляд, добавление второго сервера в кластер 1С не должно вызывать проблем – все просто должно работать. Но на практике дело обстоит иначе. Несмотря на то, что все действительно работает, многие при этом сталкиваются с трудностями. Расскажем, когда нужно задуматься о втором сервере 1С в кластере, какие особенности работы второго сервиса с файлами и сервисами, и какие настройки ТНФ можно сделать для лицензий ПРОФ и КОРП.

31.10.2024    38075    a.doroshkevich    23    

89

Запросы Разработчик 1С:Предприятие 8 1C:Бухгалтерия Бесплатно (free)

Столкнулся с интересной ситуацией, которую хотел бы разобрать, ввиду её неочевидности. Речь пойдёт про использование функции запроса АВТОНОМЕРЗАПИСИ() и проблемы, которые могут возникнуть.

11.10.2024    24579    XilDen    40    

117

HighLoad оптимизация Запросы

Очень немногие из тех, кто занимается поддержкой MS SQL, работают с хранилищем запросов. А ведь хранилище запросов – это очень удобный, мощный и, главное, бесплатный инструмент, позволяющий быстро найти и локализовать проблему производительности и потребления ресурсов запросами. В статье расскажем о том, как использовать хранилище запросов в MS SQL и какие плюсы и минусы у него есть.

11.10.2023    29491    skovpin_sa    15    

109
Комментарии
Подписаться на ответы Инфостарт бот Сортировка: Древо развёрнутое
Свернуть все
1. Antonio1C 18.10.26 17:51 Сейчас в теме
Похоже статья для ИИ агентов. Спасибо.
2. Konstmax13 17 22.10.26 07:35 Сейчас в теме
(1) Скорее для людей, которые работают вместе с агентом. Порядок диагностики тот же, что и без ИИ, просто записан так, чтобы его можно было отдать агенту как правило.
3. triviumfan 103 22.10.26 22:21 Сейчас в теме
Длительность в микросекундах, 20 000 000 означает 20 секунд

Уже давно duration – длительность события в сотнях микросекунд. Очередной нейровинегрет для буратин.
Пора уже модераторам придумать какую-то верификацию статей перед публикацией - кругом AI-madness.
Konstmax13; +1 – Ответить
4. Konstmax13 17 23.10.26 11:00 Сейчас в теме
(3)
сотнях микросекунд


(3) Спасибо, что придрались к цифре: проверять такие вещи полезно. Проверил на живом логе нашей 8.5.1, вот четыре DBMSSQL одного сеанса подряд (в начале строки время окончания события, после дефиса duration):

11:26.787 -239572998
15:31.196 -244143998
19:11.752 -198242998
22:30.483 -198698998

Если duration в микросекундах, запросы встают на шкалу впритык: каждый следующий начинается через 0,27 с, 22 с и 0,03 с после окончания предыдущего. Если в сотнях микросекунд, первый запрос шел бы 6,6 часа, хотя между окончаниями соседних всего 4 минуты.

И самое наглядное: у всех четырех событий один и тот же OSThread=47196 и SessionID=64. Один поток не выполняет два SQL одновременно. В микросекундах они идут строго друг за другом, в сотнях микросекунд четыре запроса по 5-7 часов наложились бы друг на друга в одном потоке. Так не бывает.

Третья проверка: фильтр стоял <gt property="duration" value="20000000"/>, и в лог попали запросы по 200-240 с. При сотнях микросекунд это был бы порог 2000 с, и ни один из них в лог бы не попал.

Сотни микросекунд действительно были, но в 8.2. В 8.3 и 8.5 это микросекунды, отсюда и шесть знаков после секунд в самой строке.

Так что в статье все верно, а «нейровинегрет» в этот раз оказался проверяемым. Если у вас есть лог, где выходит иначе, приносите, разберем вместе.
5. triviumfan 103 23.10.26 11:39 Сейчас в теме
(4) Мне лень проверять, достаточно зайти на ИТС:
https://its.1c.ru/db/v8327doc#bookmark:adm:TI000000397
Тамашний пример:
<gt property="duration" value="10000"/>

Причем текст оператора SQL будет помещен в журнал, только если он исполнялся более секунды

И в описании свойств:
Duration | Длительность события в сотнях микросекунд.
Durationus | Длительность события в микросекундах.

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

Да и тут статей предостаточно. Вот, к примеру https://infostart.ru/1c/articles/2794477/
Konstmax13; +1 – Ответить
6. Konstmax13 17 23.10.26 12:36 Сейчас в теме
(5) Вы правы, спасибо. Перепроверил по протоколу той диагностики, и он вас подтверждает: при <gt property="duration" value="20000000"/> за 11 минут работы отчета в журнал не попало ничего, а после снижения до 1000000 записались только запросы длиннее 100 с, ровно как при сотнях микросекунд. Мой довод про порог в прошлом ответе был неверным.

Путаница вышла из-за того, что единицы разные: в фильтре logcfg.xml duration задается в сотнях микросекунд (для микросекунд есть durationus), а в самой строке журнала, вроде -239572998, длительность пишется в микросекундах. Это я и проверял по шкале времени, но вы говорили про фильтр.

Статью уже исправил: пример с порогом 20 с теперь value="200000", с пометкой UPD и благодарностью вам. Исправление появится после модерации.
triviumfan; +1 – Ответить
Для отправки сообщения требуется регистрация/авторизация