Как отследить и диагностировать запрос 1С, который периодически выполняется слишком долго?

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

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

В этой статье мы подробно разберем, как программно замерить время выполнения такого "плавающего" запроса, не прерывая его, и как использовать полученную информацию для глубокой диагностики и устранения первопричины проблемы.

Шаг 1: Организация программного контроля времени выполнения

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

Рассмотрим пошаговый алгоритм:

  1. Подготовка процедуры для фонового задания. Создадим экспортную процедуру в общем серверном модуле, которая будет выполнять наш проблемный запрос. Это важно, так как фоновые задания могут вызывать только экспортные процедуры из общих модулей с установленным флагом "Сервер".
  2. Запуск фонового задания. В основном коде мы будем запускать эту процедуру асинхронно с помощью метода ФоновыеЗадания.Выполнить().
  3. Контроль времени. После запуска мы можем периодически проверять состояние задания и время, прошедшее с момента старта. Для этого удобно использовать обработчик ожидания.

Посмотрим на пример реализации.

Допустим, у нас есть общий модуль МоиДлительныеОперации.


// В общем модуле МоиДлительныеОперации
&НаСервере
Процедура ВыполнитьПроблемныйЗапрос(ПараметрыЗапроса) Экспорт

    // Здесь находится ваш код выполнения запроса
    Запрос = Новый Запрос;
    Запрос.Текст = 
        "ВЫБРАТЬ
        |    Номенклатура.Ссылка
        |ИЗ
        |    Справочник.Номенклатура КАК Номенклатура
        |ГДЕ
        |    Номенклатура.ЭтоГруппа = ЛОЖЬ";
    
    // ... установка параметров ...
    
    Результат = Запрос.Выполнить().Выгрузить();
    
    // Делаем что-то с результатом
    
КонецПроцедуры

Теперь в том месте, где нужно выполнить запрос и проконтролировать его время, напишем следующий код. Например, в форме.


&НаКлиенте
Процедура ВыполнитьЗапросСКонтролем(Команда)
    
    ВремяНачала = ТекущаяДата();
    
    // Запускаем фоновое задание
    Параметры = Новый Массив;
    // Добавляем сюда параметры, необходимые для запроса
    // Параметры.Добавить(НужныйПараметр); 
    
    ФоновоеЗадание = ЗапуститьФоновоеЗадание(Параметры);
    
    // Подключаем обработчик ожидания для контроля
    // Он будет срабатывать каждые 5 секунд
    ОписаниеОповещения = Новый ОписаниеОповещения("ПослеПроверкиЗадания", ЭтотОбъект);
    ПодключитьОбработчикОжидания("ПроверитьДлительностьЗадания", 5, Ложь, ОписаниеОповещения);
    
КонецПроцедуры


&НаСервереБезКонтекста
Функция ЗапуститьФоновоеЗадание(ПараметрыВыполнения)
    
    Возврат ФоновыеЗадания.Выполнить("МоиДлительныеОперации.ВыполнитьПроблемныйЗапрос", ПараметрыВыполнения);
    
КонецФункции


&НаКлиенте
Процедура ПроверитьДлительностьЗадания(ДополнительныеПараметры)
    
    // Здесь будет логика проверки
    // Предположим, что мы сохранили объект фонового задания и время начала в реквизиты формы
    // Например, ЭтотОбъект.СохраненноеЗадание и ЭтотОбъект.ВремяНачалаЗадания
    
    Если ЭтотОбъект.СохраненноеЗадание = Неопределено Тогда
        // Задание еще не создано или уже завершилось
        ОтключитьОбработчикОжидания("ПроверитьДлительностьЗадания");
        Возврат;
    КонецЕсли;

    ПрошлоВремени = ТекущаяДата() - ЭтотОбъект.ВремяНачалаЗадания;
    МаксимальноДопустимоеВремя = 60; // Устанавливаем порог в 60 секунд
    
    Если ПрошлоВремени > МаксимальноДопустимоеВремя И НЕ ЭтотОбъект.СообщениеУжеОтправлено Тогда
        
        // ВРЕМЯ ПРЕВЫШЕНО!
        // Выполняем нужные действия:
        // 1. Записываем сообщение в журнал регистрации
        // 2. Отправляем уведомление администратору
        // 3. Запускаем сбор каких-либо диагностических данных
        Сообщить("Внимание! Запрос выполняется уже более " + МаксимальноДопустимоеВремя + " секунд!");
        
        // Устанавливаем флаг, чтобы не отправлять сообщения каждую секунду
        ЭтотОбъект.СообщениеУжеОтправлено = Истина;
    КонецЕсли;
    
    // Проверяем, не завершилось ли задание
    СостояниеЗадания = ПолучитьСостояниеЗадания(ЭтотОбъект.СохраненноеЗадание.УникальныйИдентификатор);
    
    Если СостояниеЗадания.Завершено Тогда
        Сообщить("Задание успешно завершено!");
        ОтключитьОбработчикОжидания("ПроверитьДлительностьЗадания");
        ЭтотОбъект.СохраненноеЗадание = Неопределено;
    КонецЕсли;

КонецПроцедуры

&НаСервереБезКонтекста
Функция ПолучитьСостояниеЗадания(УИД)
    
    Возврат ФоновыеЗадания.Получить(УИД);
    
КонецФункции

Этот подход позволяет нам, не прерывая выполнение запроса, зафиксировать факт аномально долгой работы и инициировать сбор диагностической информации, о которой мы поговорим далее.

Шаг 2: Диагностика реальных причин "зависания"

Итак, мы научились ловить моменты, когда запрос начинает "тормозить". Теперь наша главная задача — понять, почему это происходит. Как уже отмечалось, причина редко кроется в самом тексте запроса, если он не меняется. Проанализируем самые частые "виновники".

Причина 1: Блокировки на уровне СУБД

Это самая распространенная причина. Ваш запрос пытается прочитать или изменить данные, которые в этот же момент заблокированы другой транзакцией (например, проведением документа, расчетом себестоимости или другим отчетом). Ваш сеанс будет терпеливо ждать, пока блокировка не будет снята. Это ожидание и выглядит как "зависание".

Как обнаружить блокировки:

Причина 2: Неоптимальные планы выполнения запросов

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

Почему это происходит и что делать:

Шаг 3: Использование встроенных инструментов 1С

Платформа 1С предоставляет мощные средства для анализа производительности, которые обязательно нужно использовать.

Технологический журнал (ТЖ)

Мы уже упоминали ТЖ в контексте блокировок, но его главная сила — в отслеживании взаимодействия с СУБД. Для анализа долгих запросов настройте сбор события SDBL. В файле настройки logcfg.xml можно указать порог длительности, например, записывать в лог все запросы к базе, которые выполняются дольше 1000 миллисекунд (1 секунды).

Когда проблема воспроизведется, в логах ТЖ вы найдете:

Это позволяет со стопроцентной точностью определить, какой именно запрос тормозит и при каких обстоятельствах.

Замеры производительности (из Библиотеки Стандартных Подсистем)

Если проблема не в одном монолитном запросе, а в сложной логике с множеством мелких запросов в цикле, поможет инструмент "Оценка производительности" из БСП. Вы можете программно или интерактивно включить замер для нужного участка кода. Система соберет детальную статистику о том, сколько раз вызывалась каждая процедура/функция и сколько суммарно времени заняло ее выполнение. Это поможет найти "узкое горлышко" в вашем алгоритме.

Итоговый план действий

Для решения проблемы с "плавающими" по производительности запросами рекомендуем использовать комплексный подход:

  1. Внедрите программный контроль. Оберните выполнение проблемного запроса в фоновое задание, как показано в примере выше. Настройте оповещение при превышении порогового времени.
  2. Настройте технологический журнал. Заранее подготовьте конфигурационный файл ТЖ для сбора событий SDBL (с порогом длительности) и TLOCK.
  3. Ловите момент. Когда сработает ваше оповещение о долгом запросе, немедленно включайте сбор логов ТЖ (если он не работает постоянно) и анализируйте состояние СУБД на предмет блокировок.
  4. Анализируйте данные. Сопоставьте информацию из вашего программного журнала, логов ТЖ и данных мониторинга СУБД. Это позволит точно определить причину: блокировка, неоптимальный план запроса или общая высокая нагрузка на сервер.

Такой системный подход поможет не только решить текущую проблему, но и выстроить эффективный процесс мониторинга производительности вашей системы 1С.

← На главную